Railway Operation Simulator  v2.14.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
251  SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 // Track functions
1108 // ---------------------------------------------------------------------------
1109 
1110 // ---------------------------------------------------------------------------
1111 
1112 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1113 {
1114  TypeOfRoute = 0;
1115  ReducedTimePenalty = false;
1116  BarrierState = Up;
1117  ChangeDuration = 0.0;
1118  BaseElementSpeedTag = 1;
1119  HLoc = 0;
1120  VLoc = 0;
1121  StartTime = TDateTime(0);
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1125 
1127 {
1128 // CurrentSpeedButtonTag = 0; //not assigned yet
1129 
1130  HLocMin = 2000000000;
1131  VLocMin = 2000000000;
1132  HLocMax = -2000000000;
1133  VLocMax = -2000000000;
1134  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1135  CopyFlag = false; // only true for copying, so names aren't copied
1136  AnsiString NL = '\n';
1137 
1138  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1139  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1140  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1141  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1142 
1147 
1148  int InternalLinkCheckArray[9][2] =
1149  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1150 
1151 /* array of valid link values for 'old' location and 'new' location, where
1152  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1153 
1154  for(int x = 0; x < 9; x++)
1155  {
1156  for(int y = 0; y < 2; y++)
1157  {
1158  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1159  }
1160  }
1161 
1162 // Platform and default track element values
1163  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1164 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1165  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1166  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1167  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1168  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1169  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1170  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1171  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1172  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1173 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1174 
1175  int HVArray[10][2] =
1176  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1177 
1178  for(int x = 0; x < 10; x++)
1179  {
1180  for(int y = 0; y < 2; y++)
1181  {
1182  LinkHVArray[x][y] = HVArray[x][y];
1183  }
1184  }
1185  TrackFinished = false;
1186 // DistancesSet = false;
1187 
1188  TSigElement TempSigTable[40] = // original four aspect
1189  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1190  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1191 
1192  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1193  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1194 
1197 
1198  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1199  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1200 
1201  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1202  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1203  {75, 4, RailGraphics->gl75}};
1204 
1205  for(int x = 0; x < 40; x++)
1206  {
1207  SigTable[x] = TempSigTable[x];
1208  }
1209 
1210  TSigElement TempSigTableThreeAspect[40] =
1211  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1212  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1213 
1214  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1215  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1216 
1217  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1218  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1219 
1220  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1221  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1222 
1223  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1224  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1225  {75, 4, RailGraphics->gl75}};
1226 
1227  for(int x = 0; x < 40; x++)
1228  {
1229  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1230  }
1231 
1232  TSigElement TempSigTableTwoAspect[40] =
1233  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1234  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1235 
1236  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1237  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1238 
1239  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1240  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1241 
1242  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1243  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1244 
1245  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1246  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1247  {75, 4, RailGraphics->gl75}};
1248 
1249  for(int x = 0; x < 40; x++)
1250  {
1251  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1252  }
1253 
1254  TSigElement TempSigTableGroundSignal[40] =
1258 
1262 
1266 
1270 
1271  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1274 
1275  for(int x = 0; x < 40; x++)
1276  {
1277  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1278  }
1279 
1280  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1281  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1282  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1283 
1284  for(int x = 0; x < 8; x++)
1285  {
1286  FailedSigTable[x] = TempFailedSigTable[x];
1287  }
1288 
1289  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1290  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1291  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1292 
1293  for(int x = 0; x < 8; x++)
1294  {
1295  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1296  }
1297 
1298 /*
1299  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1300  a single location. These are as follows:-
1301  Directly Adjacent = up, down, left or right - NOT diagonal.
1302  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1303  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1304  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1305 
1306  //t 76
1307  //b 77
1308  //l 78
1309  //r 79
1310  //c 96
1311  //v fb 129
1312  //h fb 130
1313  //v underpass 145
1314  //h underpass 146
1315  //n 131
1316 */
1317 
1318  int Tag76[25][3] =
1319  {{-1, 0, 96}, // c top plat
1320  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1321  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1322  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1323  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1324  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1325  {0, 0, 129}, {0, -1, 145}, // v up
1326  {0, 0, 145}};
1327 
1328  for(int x = 0; x < 25; x++)
1329  {
1330  for(int y = 0; y < 3; y++)
1331  {
1332  Tag76Array[x][y] = Tag76[x][y];
1333  }
1334  }
1335 
1336  int Tag77[25][3] =
1337  {{-1, 0, 96}, // c bot plat
1338  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1339  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1340  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1341  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1342  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1343  {0, 0, 129}, {0, 1, 145}, // v up
1344  {0, 0, 145}};
1345 
1346  for(int x = 0; x < 25; x++)
1347  {
1348  for(int y = 0; y < 3; y++)
1349  {
1350  Tag77Array[x][y] = Tag77[x][y];
1351  }
1352  }
1353 
1354  int Tag78[25][3] =
1355  {{-1, 0, 96}, // c left plat
1356  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1357  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1358  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1359  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1360  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1361  {0, 0, 130}, {-1, 0, 146}, // h up
1362  {0, 0, 146}};
1363 
1364  for(int x = 0; x < 25; x++)
1365  {
1366  for(int y = 0; y < 3; y++)
1367  {
1368  Tag78Array[x][y] = Tag78[x][y];
1369  }
1370  }
1371 
1372  int Tag79[25][3] =
1373  {{-1, 0, 96}, // c right plat
1374  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1375  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1376  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1377  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1378  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1379  {0, 0, 130}, {1, 0, 146}, // h up
1380  {0, 0, 146}};
1381 
1382  for(int x = 0; x < 25; x++)
1383  {
1384  for(int y = 0; y < 3; y++)
1385  {
1386  Tag79Array[x][y] = Tag79[x][y];
1387  }
1388  }
1389 
1390  int Tag96[28][3] =
1391  {{-1, 0, 96}, // c //concourse
1392  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1393  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1394  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1395  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1396  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1397  {0, -1, 129}, {1, 0, 130}, // h fb
1398  {-1, 0, 130}, {0, 1, 145}, // v up
1399  {0, -1, 145}, {1, 0, 146}, // h up
1400  {-1, 0, 146}};
1401 
1402  for(int x = 0; x < 28; x++)
1403  {
1404  for(int y = 0; y < 3; y++)
1405  {
1406  Tag96Array[x][y] = Tag96[x][y];
1407  }
1408  }
1409 
1410  int Tag129[8][3] = // vert fb
1411  {{0, -1, 96}, // c
1412  {0, -1, 77}, // b
1413  {0, -1, 129}, // v fb
1414 
1415  {0, 1, 96}, // c
1416  {0, 1, 76}, // t
1417  {0, 1, 129}, // v fb
1418 
1419  {0, 0, 76}, // t
1420  {0, 0, 77}}; // b
1421 
1422  for(int x = 0; x < 8; x++)
1423  {
1424  for(int y = 0; y < 3; y++)
1425  {
1426  Tag129Array[x][y] = Tag129[x][y];
1427  }
1428  }
1429 
1430  int Tag145[8][3] = // vert up
1431  {{0, -1, 96}, // c
1432  {0, -1, 77}, // b
1433  {0, -1, 145}, // v fb
1434 
1435  {0, 1, 96}, // c
1436  {0, 1, 76}, // t
1437  {0, 1, 145}, // v fb
1438 
1439  {0, 0, 76}, // t
1440  {0, 0, 77}}; // b
1441 
1442  for(int x = 0; x < 8; x++)
1443  {
1444  for(int y = 0; y < 3; y++)
1445  {
1446  Tag145Array[x][y] = Tag145[x][y];
1447  }
1448  }
1449 
1450  int Tag130[8][3] = // hor fb
1451  {{-1, 0, 96}, // c
1452  {-1, 0, 79}, // r
1453  {-1, 0, 130}, // h fb
1454 
1455  {1, 0, 96}, // c
1456  {1, 0, 78}, // l
1457  {1, 0, 130}, // h fb
1458 
1459  {0, 0, 78}, // l
1460  {0, 0, 79}}; // r
1461 
1462  for(int x = 0; x < 8; x++)
1463  {
1464  for(int y = 0; y < 3; y++)
1465  {
1466  Tag130Array[x][y] = Tag130[x][y];
1467  }
1468  }
1469 
1470  int Tag146[8][3] = // hor up
1471  {{-1, 0, 96}, // c
1472  {-1, 0, 79}, // r
1473  {-1, 0, 146}, // h fb
1474 
1475  {1, 0, 96}, // c
1476  {1, 0, 78}, // l
1477  {1, 0, 146}, // h fb
1478 
1479  {0, 0, 78}, // l
1480  {0, 0, 79}}; // r
1481 
1482  for(int x = 0; x < 8; x++)
1483  {
1484  for(int y = 0; y < 3; y++)
1485  {
1486  Tag146Array[x][y] = Tag146[x][y];
1487  }
1488  }
1489 
1490  int Tag131[4][3] =
1491  {{-1, 0, 131}, // n
1492  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1493 
1494  for(int x = 0; x < 4; x++)
1495  {
1496  for(int y = 0; y < 3; y++)
1497  {
1498  Tag131Array[x][y] = Tag131[x][y];
1499  }
1500  }
1501 
1502  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1503  {
1504  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1505  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1506  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1507  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1508  140, 144, 145, 146
1509  };
1510 
1511  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1512  {
1513  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1514  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1515  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1516  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1517  141, 144, 145, 146
1518  };
1519 
1520  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1521  {
1522  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1523  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1524  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1525  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1526  141, 144, 146, 145
1527  };
1528 
1529  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1530  {
1531  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1532  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1533  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1534  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1535  140, 144, 146, 145
1536  };
1537 
1538  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1539  {
1540  FlipArray[x] = InternalFlipArray[x];
1541  MirrorArray[x] = InternalMirrorArray[x];
1542  RotRightArray[x] = InternalRotRightArray[x];
1543  RotLeftArray[x] = InternalRotLeftArray[x];
1544  }
1545 }
1546 
1547 // ---------------------------------------------------------------------------
1549 {
1550 // delete TrackVectorPtr;
1551 // delete FixedTrackArrayPtr;
1552  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1553 
1554  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1555  {
1556  delete UGMIt->second;
1557  UGMIt++;
1558  }
1559  delete GapFlashGreen;
1560  delete GapFlashRed;
1561  // all the rest are cleared by the relevant automatic destructors
1562 }
1563 
1564 // ---------------------------------------------------------------------------
1565 
1567 {
1568  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1569  {
1570 // loc 0 not used, set to bmSolidBgnd
1574 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1594  };
1595 
1596  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1597  {
1598 // loc 0 not used, set to smSolidBgnd
1602 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1621  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1622  };
1623 
1624 // track types
1625  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1626  {
1627  Erase, // 1 0
1628  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1629  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1630  Crossover, Crossover, // 2 15-16
1631  Unused, // 17 (was for text in earlier development) //1 17
1634  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1638  Platform, Platform, Platform, Platform, // 4 76-79
1641  Concourse, // 1 96
1644  Simple, Simple, Simple, Simple, // 4 125-128
1645  FootCrossing, FootCrossing, // 2 129-130
1646  NamedNonStationLocation, // 1 131
1647  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1648  Simple, Simple, Simple, Simple, // 4 140-143
1649  LevelCrossing, // 1 144
1650  FootCrossing, FootCrossing // 2 145 & 146
1651  };
1652 
1653 // links
1654  int Links[FirstUnusedSpeedTagNumber][4] =
1655  {{-1, -1, -1, -1}, // erase element
1656  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1657  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1658 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1659  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1660  {-1, -1, -1, -1}, // unused
1661  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1662  {2, 7, -1, -1}, // simple
1663  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1664 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1665 // (or right diverging if no straight)
1666  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1667  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1668  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1669  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1670  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1671  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1672  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1673  {-1, -1, -1, -1}, // Concourse
1674  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1675  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1676  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1677  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1678  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1679  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1680  {-1, -1, -1, -1}, // NamedNonStationLocation
1681  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1682 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1683  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1684  {-1, -1, -1, -1}, // level crossing
1685  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1686  };
1687 
1689  {{NotSet, NotSet, NotSet, NotSet}, // unused
1693  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1695  {NotSet, NotSet, NotSet, NotSet}, // unused
1699  {Connection, Connection, NotSet, NotSet}, // simple
1703  {Lead, Trail, Lead, Trail}, // points
1705  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1713  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1719  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1728  {Connection, Connection, NotSet, NotSet}, // Arrows
1730  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1732  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1734  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1735  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1736  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1737  };
1738 
1739  for(int x = 0; x < 17; x++)
1740  {
1741  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1742  }
1743  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1744 // 17 was the old text value so don't want any graphics (now disused)
1745  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1746  {
1747  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1748  }
1749 }
1750 
1751 // ---------------------------------------------------------------------------
1752 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1753  ExistingGraphicLoaded(false), Width(16), Height(16)
1754 {
1755  OriginalGraphic = new Graphics::TBitmap;
1756  OriginalGraphic->PixelFormat = pf8bit;
1757  OriginalGraphic->Width = Width;
1758  OriginalGraphic->Height = Height;
1759  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1760 }
1761 
1762 // ---------------------------------------------------------------------------
1763 
1764 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1765  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1766 {
1767  OriginalGraphic = new Graphics::TBitmap;
1768  OriginalGraphic->PixelFormat = pf8bit;
1769  OriginalGraphic->Width = Width;
1770  OriginalGraphic->Height = Height;
1771  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1772 }
1773 
1774 // ---------------------------------------------------------------------------
1775 
1777 {
1778  delete OriginalGraphic;
1779 }
1780 
1781 // ---------------------------------------------------------------------------
1782 
1783 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1784 {
1785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1786  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1787  VPos = VPosIn;
1788  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1789 
1790  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1791  SourceRect.init(Left, Top, Left + Width, Top + Height);
1792  ScreenSourceSet = true;
1793  Utilities->CallLogPop(422);
1794 }
1795 
1796 // ---------------------------------------------------------------------------
1797 
1799 {
1800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1801  if(!OverlayLoaded)
1802  {
1803  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1804  }
1805  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1806  {
1807  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1808  }
1809  if(!ScreenSourceSet)
1810  {
1811  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1812  }
1813  if(ExistingGraphicLoaded) // can only call one of the load functions
1814  {
1815  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1816  }
1817  if(OverlayPlotted) // don't load from screen if overlay plotted
1818  {
1819  Utilities->CallLogPop(775);
1820  return;
1821  }
1822  TRect DestRect(0, 0, Width, Height);
1823 
1825  OriginalLoaded = true;
1826  ScreenGraphicLoaded = true;
1827  Utilities->CallLogPop(423);
1828 }
1829 
1830 // ---------------------------------------------------------------------------
1831 
1832 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1833 /*
1834  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1835 */
1836 {
1837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1838  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1839  if(!OverlayLoaded)
1840  {
1841  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1842  }
1843  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1844  {
1845  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1846  }
1847  if(ScreenGraphicLoaded) // can only call one of the load functions
1848  {
1849  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1850  }
1851  Width = WidthIn;
1852  Height = HeightIn;
1853  OriginalGraphic->Width = Width;
1854  OriginalGraphic->Height = Height;
1855  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1856  VPos += VOffset;
1857  TRect DestRect(0, 0, Width, Height);
1858 
1859  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1860  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1861  OriginalLoaded = true;
1862  ExistingGraphicLoaded = true;
1863  Utilities->CallLogPop(424);
1864 }
1865 
1866 // ---------------------------------------------------------------------------
1867 
1868 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1869 {
1870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1871  OverlayGraphic = Overlay;
1872  OverlayLoaded = true;
1873  Utilities->CallLogPop(425);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1881  if(!OverlayLoaded)
1882  {
1883  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1884  }
1885  if(!OverlayPlotted)
1886  {
1887  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1888  Disp->Update();
1889  OverlayPlotted = true;
1890  }
1891  Utilities->CallLogPop(426);
1892 }
1893 
1894 // ---------------------------------------------------------------------------
1895 
1897 {
1898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1899  if(OverlayPlotted)
1900  {
1901  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1902  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1903  {
1904  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1905  }
1906  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1907  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1908  OverlayPlotted = false;
1909  }
1910  Utilities->CallLogPop(427);
1911 }
1912 
1913 // ---------------------------------------------------------------------------
1914 
1916 {
1917  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1918  bool TrackPresent = false;
1919 
1920  if(InactiveTrackVector.size() != 0)
1921  {
1922  Utilities->CallLogPop(1333);
1923  return(false);
1924  }
1925  else if(TrackVector.size() == 0)
1926  {
1927  Utilities->CallLogPop(1334);
1928  return(true);
1929  }
1930  else
1931  {
1932  for(unsigned int x = 0; x < TrackVector.size(); x++)
1933  {
1934  if((TrackElementAt(1042, x).SpeedTag != 0))
1935  {
1936  TrackPresent = true;
1937  }
1938  }
1939  }
1940  Utilities->CallLogPop(1335);
1941  return(!TrackPresent);
1942 }
1943 
1944 // ---------------------------------------------------------------------------
1945 
1946 bool TTrack::NoActiveTrack(int Caller)
1947 {
1948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1949  bool TrackPresent = false;
1950 
1951  if(TrackVector.size() == 0)
1952  {
1953  Utilities->CallLogPop(1582);
1954  return(true);
1955  }
1956  else
1957  {
1958  for(unsigned int x = 0; x < TrackVector.size(); x++)
1959  {
1960  if((TrackElementAt(1043, x).SpeedTag != 0))
1961  {
1962  TrackPresent = true;
1963  }
1964  break;
1965  }
1966  }
1967  Utilities->CallLogPop(1583);
1968  return(!TrackPresent);
1969 }
1970 
1971 // ---------------------------------------------------------------------------
1972 
1973 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1974 {
1975  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1976  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1977  TrackEraseSuccessfulFlag = false;
1978 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1979 // since have to match platforms as well as track
1980 // used to set TrackFinished to false if an element erased
1981 
1982  ErasedTrackVectorPosition = -1; // marker for no element erased
1983  AnsiString SName = "", ErrorString;
1985  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1986  TTrackMapIterator TrackMapPtr;
1987  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1988 
1989  if(TrackVector.size() != 0)
1990  {
1991  TrackMapKeyPair.first = HLocInput;
1992  TrackMapKeyPair.second = VLocInput;
1993  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1994  if(TrackMapPtr != TrackMap.end())
1995  {
1996  bool FoundFlag;
1997  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1998  if(FoundFlag) // should find it as it's in the map
1999  {
2000  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2001  {
2002  SName = TrackElementAt(1, VecPos).LocationName;
2003  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2004  if(ErrorString != "")
2005  {
2006  throw Exception(ErrorString + " for EraseTrackElement 1");
2007  }
2008  LocationNameMultiMap.erase(SNIt);
2009  }
2010  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2011  // ensure erase vector element before map element as iterator no longer valid after a map erase
2012  TrackMap.erase(TrackMapPtr);
2013  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2014  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2016  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2017  if(SName != "")
2018  {
2019  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2020  int HPos, VPos;
2021  if(TextHandler->FindText(1, SName, HPos, VPos))
2022  {
2023  if(TextHandler->TextErase(5, HPos, VPos, SName))
2024  {
2025  ;
2026  } // condition not used
2027 
2028  }
2029  }
2030  ErasedTrackVectorPosition = VecPos;
2031  TrackEraseSuccessfulFlag = true;
2032  }
2033  }
2034  }
2035  if(InactiveTrackVector.size() != 0)
2036  {
2037  unsigned int VecPos;
2038  InactiveTrackMapKeyPair.first = HLocInput;
2039  InactiveTrackMapKeyPair.second = VLocInput;
2040  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2041  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2042  {
2043  SName = "";
2044  VecPos = InactiveTrack2MultiMapIterator->second;
2045  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2046  {
2047  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2048  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2049  if(ErrorString != "")
2050  {
2051  throw Exception(ErrorString + " for EraseTrackElement 2A");
2052  }
2053  LocationNameMultiMap.erase(SNIt);
2054  }
2055  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2056  // ensure erase vector element before map element as iterator no longer valid after a map erase
2057  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2058  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2059  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2061  TrackEraseSuccessfulFlag = true;
2062  if(SName != "")
2063  {
2064  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2065  int HPos, VPos;
2066  if(TextHandler->FindText(2, SName, HPos, VPos))
2067  {
2068  if(TextHandler->TextErase(6, HPos, VPos, SName))
2069  {
2070  ;
2071  } // condition not used
2072 
2073  }
2074  }
2075  }
2076  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2077  {
2078  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2079  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2080  {
2081  SName = "";
2082  VecPos = InactiveTrack2MultiMapIterator->second;
2083  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2084  {
2085  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2086  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2087  if(ErrorString != "")
2088  {
2089  throw Exception(ErrorString + " for EraseTrackElement 2B");
2090  }
2091  LocationNameMultiMap.erase(SNIt);
2092  }
2093  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2094  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2095  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2097  if(SName != "")
2098  {
2099  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2100  int HPos, VPos;
2101  if(TextHandler->FindText(3, SName, HPos, VPos))
2102  {
2103  if(TextHandler->TextErase(7, HPos, VPos, SName))
2104  {
2105  ;
2106  } // condition not used
2107 
2108  }
2109  }
2110  }
2111  }
2112  }
2113  if(TrackEraseSuccessfulFlag)
2114  {
2115  CalcHLocMinEtc(2);
2116  SetTrackFinished(false);
2117  }
2118  if(InternalChecks)
2119  {
2120  CheckMapAndTrack(1); // test
2121  CheckMapAndInactiveTrack(1); // test
2122  CheckLocationNameMultiMap(6); // test
2123  }
2124  Utilities->CallLogPop(428);
2125 }
2126 
2127 // ---------------------------------------------------------------------------
2128 
2129 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2130 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2131 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2132 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2133 {
2134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2135  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2136  bool PlatAllowedFlag = false;
2137 
2138  TrackLinkingRequiredFlag = false;
2139 /*
2140  Not erase, that covered separately.
2141  First check if Current SpeedButton assigned, then check if a platform and only
2142  permit if an appropriate trackpiece already there & not a same platform there.
2143  - can't enter a platform without track first.
2144  Then for non-platforms, check if a track piece already present at location &
2145  reject if so.
2146 */
2147 
2148  TLocationNameMultiMapEntry LocationNameEntry;
2149 
2150  LocationNameEntry.first = "";
2151  if(CurrentTag == 0)
2152  {
2153  Utilities->CallLogPop(429);
2154  return; // not assigned yet
2155  }
2156  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2157 
2158  TempTrackElement.HLoc = HLocInput;
2159  TempTrackElement.VLoc = VLocInput;
2160  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2161 // new at version 0.6 - set signal aspect depending on build mode
2162 
2163  if(TempTrackElement.TrackType == SignalPost)
2164  {
2165  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2166  // pasting a SignalPost can only have values 1 to 4
2167  {
2169  {
2170  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2171  }
2173  {
2174  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2175  }
2177  {
2178  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2179  }
2180  else
2181  {
2182  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2183  }
2184  }
2185  else if(Aspect == 1)
2186  {
2187  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2188  }
2189  else if(Aspect == 2)
2190  {
2191  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2192  }
2193  else if(Aspect == 3)
2194  {
2195  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2196  }
2197  else
2198  {
2199  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2200  }
2201  }
2202  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2203  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2204  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2205  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2206 
2207  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2208  {
2210  {
2211  NonStationOrLevelCrossingPresent = true;
2212  }
2213  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2214  {
2215  NonStationOrLevelCrossingPresent = true;
2216  }
2217  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2218  {
2219  PlatformPresent = true;
2220  }
2221  // no need to check IMPair.second since if that exists it is because .first is a platform
2222  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2223  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2224  }
2225 // check platforms
2226  if(TempTrackElement.TrackType == Platform)
2227  {
2228  if(FoundFlag) // active track element already there
2229  {
2230  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2231  {
2232  ;
2233  }
2234  // same platform type already there so above keeps PlatAllowedFlag false
2235  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2236  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2237  {
2238  PlatAllowedFlag = true;
2239  }
2240  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2241  {
2242  PlatAllowedFlag = true;
2243  }
2244  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2245  {
2246  PlatAllowedFlag = true;
2247  }
2248  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2249  {
2250  PlatAllowedFlag = true;
2251  }
2252  if(PlatAllowedFlag)
2253  {
2254  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2255  TrackPush(1, TempTrackElement);
2256  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2257  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2258  // Must be called AFTER TrackPush
2259  // No need to plot the element - Clearand ... called after this function called
2260  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2261  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2262 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2263 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2264 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2265  if(InternalChecks)
2266  {
2267  CheckMapAndInactiveTrack(5); // test
2268  CheckLocationNameMultiMap(4); // test
2269  }
2270  Utilities->CallLogPop(430);
2271  return;
2272  }
2273  } // if(FoundFlag)
2274 
2275  Utilities->CallLogPop(431);
2276  return;
2277  } // if platform
2278 
2279 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2280  if(TempTrackElement.TrackType == NamedNonStationLocation)
2281  {
2282  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2283  (!FoundFlag && !InactiveFoundFlag))
2284  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2285  {
2286  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2287  TrackPush(2, TempTrackElement);
2288  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2289  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2290  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2291  {
2292 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2293 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2294 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2295  }
2296  if(InternalChecks)
2297  {
2298  CheckMapAndInactiveTrack(11); // test
2299  CheckLocationNameMultiMap(12); // test
2300  }
2301  Utilities->CallLogPop(432);
2302  return;
2303  }
2304  else
2305  {
2306  Utilities->CallLogPop(433);
2307  return;
2308  }
2309  }
2310 // check if a level crossing - OK if placed on a plain straight track
2311  if(TempTrackElement.TrackType == LevelCrossing)
2312  {
2313  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2314  {
2315  TrackPush(11, TempTrackElement);
2316  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2317 // no need for reference to LC element as can't be open
2318  TrackLinkingRequiredFlag = true;
2319  Utilities->CallLogPop(1907);
2320  return;
2321  }
2322  else
2323  {
2324  Utilities->CallLogPop(1906);
2325  return; // was a level crossing but can't place it for some reason
2326  }
2327  }
2328 
2329 // check if another element already there
2330  else if(FoundFlag || InactiveFoundFlag)
2331  {
2332  Utilities->CallLogPop(434);
2333  return; // something already there (active or inactive track)
2334  }
2335 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2336 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2337 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2338 // do this after pushed into vector so that can use EnterLocationName
2339 
2340  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2341  {
2342  TrackPush(3, TempTrackElement);
2343  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2344  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2345  }
2346  else if(TempTrackElement.TrackType == Points)
2347  {
2348  TrackPush(4, TempTrackElement);
2349  bool BothPointFillets = true;
2350  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2351  }
2352  else if(TempTrackElement.TrackType == SignalPost)
2353  {
2354  TrackPush(10, TempTrackElement);
2355  PlotSignal(12, TempTrackElement, Display);
2356  }
2357  else
2358  {
2359  TrackPush(5, TempTrackElement);
2360  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2361  }
2362  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2363  {
2364  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2365  }
2366  if(InternalChecks)
2367  {
2368  CheckMapAndTrack(2); // test
2369  CheckMapAndInactiveTrack(2); // test
2370  CheckLocationNameMultiMap(5); // test
2371  }
2372  Utilities->CallLogPop(2062);
2373 }
2374 
2375 // ---------------------------------------------------------------------------
2376 
2377 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2378  bool InternalChecks)
2379 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2380 {
2381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2382  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2383  bool PlatAllowedFlag = false;
2384 
2385  TrackLinkingRequiredFlag = false;
2386  TLocationNameMultiMapEntry LocationNameEntry;
2387 
2388  LocationNameEntry.first = "";
2389  if(TempTrackElement.SpeedTag == 0)
2390  {
2391  Utilities->CallLogPop(2063);
2392  return; // not assigned yet
2393  }
2394  TempTrackElement.HLoc = HLocInput;
2395  TempTrackElement.VLoc = VLocInput;
2396  for(int x = 0; x < 4; x++) // unset any gaps
2397  {
2398  if(TempTrackElement.Config[x] == Gap)
2399  {
2400  TempTrackElement.ConnLinkPos[x] = -1;
2401  }
2402  TempTrackElement.Conn[x] = -1;
2403  }
2404  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2405 // new at version 0.6 - set signal aspect depending on build mode
2406  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2407  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2408 
2409  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2410  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2411  // for the active track element because these aren't set
2412  // if don't do this then get a mismatch error during map checks later
2413 
2414  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2415 
2416  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2417  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2418 
2419  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2420  {
2421  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2422  {
2423  NonStationOrLevelCrossingPresent = true;
2424  }
2425  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2426  {
2427  NonStationOrLevelCrossingPresent = true;
2428  }
2429  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2430  {
2431  PlatformPresent = true;
2432  }
2433  // no need to check IMPair.second since if that exists it is because .first is a platform
2434  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2435  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2436  }
2437 // check platforms
2438  if(TempTrackElement.TrackType == Platform)
2439  {
2440  if(FoundFlag) // active track element already there
2441  {
2442  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2443  {
2444  ;
2445  }
2446  // same platform type already there so above keeps PlatAllowedFlag false
2447  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2448  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2449  {
2450  PlatAllowedFlag = true;
2451  }
2452  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2453  {
2454  PlatAllowedFlag = true;
2455  }
2456  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2457  {
2458  PlatAllowedFlag = true;
2459  }
2460  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2461  {
2462  PlatAllowedFlag = true;
2463  }
2464  if(PlatAllowedFlag)
2465  {
2466  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2467  TrackPush(12, TempTrackElement);
2468 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2469  {
2470  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2471  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2472  }
2473  // Must be called AFTER TrackPush
2474 // No need to plot the element - Clearand ... called after this function called
2475  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2476  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2477 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2478 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2479 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2480  if(InternalChecks)
2481  {
2482  CheckMapAndInactiveTrack(12); // test
2483  CheckLocationNameMultiMap(20); // test
2484  }
2485  Utilities->CallLogPop(2064);
2486  return;
2487  }
2488  } // if(FoundFlag)
2489 
2490  Utilities->CallLogPop(2065);
2491  return;
2492  } // if platform
2493 
2494 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2495  if(TempTrackElement.TrackType == NamedNonStationLocation)
2496  {
2497  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2498  (!FoundFlag && !InactiveFoundFlag))
2499  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2500  {
2501  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2502  TrackPush(13, TempTrackElement);
2503 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2504  {
2505  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2506  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2507  }
2508  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2509  {
2510 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2511 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2512 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2513  }
2514  if(InternalChecks)
2515  {
2516  CheckMapAndInactiveTrack(13); // test
2517  CheckLocationNameMultiMap(21); // test
2518  }
2519  Utilities->CallLogPop(2066);
2520  return;
2521  }
2522  else
2523  {
2524  Utilities->CallLogPop(2067);
2525  return;
2526  }
2527  }
2528 // check if a level crossing - OK if placed on a plain straight track
2529  if(TempTrackElement.TrackType == LevelCrossing)
2530  {
2531  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2532  {
2533  TrackPush(14, TempTrackElement);
2534  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2535 // no need for reference to LC element as can't be open
2536  TrackLinkingRequiredFlag = true;
2537  Utilities->CallLogPop(2068);
2538  return;
2539  }
2540  else
2541  {
2542  Utilities->CallLogPop(2069);
2543  return; // was a level crossing but can't place it for some reason
2544  }
2545  }
2546 
2547 // check if another element already there
2548  else if(FoundFlag || InactiveFoundFlag)
2549  {
2550  Utilities->CallLogPop(2070);
2551  return; // something already there (active or inactive track)
2552  }
2553 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2554 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2555 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2556 // do this after pushed into vector so that can use EnterLocationName
2557 
2558  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2559  {
2560  TrackPush(15, TempTrackElement);
2561  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2562  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2563  }
2564  else if(TempTrackElement.TrackType == Points)
2565  {
2566  TrackPush(16, TempTrackElement);
2567  bool BothPointFillets = true;
2568  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2569  }
2570  else if(TempTrackElement.TrackType == SignalPost)
2571  {
2572  TrackPush(17, TempTrackElement);
2573  PlotSignal(14, TempTrackElement, Display);
2574  }
2575  else
2576  {
2577  TrackPush(18, TempTrackElement);
2578  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2579  }
2580  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2581  {
2582  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2583  }
2584  if(InternalChecks)
2585  {
2586  CheckMapAndTrack(12); // test
2587  CheckMapAndInactiveTrack(14); // test
2588  CheckLocationNameMultiMap(22); // test
2589  }
2590  Utilities->CallLogPop(2071);
2591 }
2592 
2593 // ---------------------------------------------------------------------------
2594 
2595 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2596 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2597 // return bool = true for success
2598 // LocError = true for location error & HLoc & VLoc to be inverted
2599 {
2600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2601  LocError = false;
2602  SetTrackFinished(false);
2603  if(TrackVector.size() == 0)
2604  {
2605  Utilities->CallLogPop(437);
2606  return(false);
2607  }
2608  if(GapsUnset(7))
2609  {
2610  if(GiveMessages)
2611  {
2612  ShowMessage("Gaps must be set before track can be validated");
2613  }
2614  Utilities->CallLogPop(1135);
2615  return(false);
2616  }
2617 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2618 // returns true for any unset gaps
2620  {
2621  // can keep this exception as protected by the GapsUnset call above
2622  throw Exception("Error, gaps unset when TryToConnectTrack called");
2623  }
2625  CheckGapMap(1); // test
2626 // Gap connections now securely defined
2627 
2628  CheckMapAndTrack(8); // test
2629 
2630 // Perform a pre-check prior to TrackMap being compiled
2631  if(GiveMessages)
2632  {
2633  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2634  {
2635  Utilities->CallLogPop(439);
2636  return(false);
2637  }
2638  }
2639  else
2640  {
2641  if(!LinkTrackNoMessages(1, false))
2642  {
2643  Utilities->CallLogPop(1131);
2644  return(false);
2645  }
2646  }
2647 // here if pre-check successful
2648  if(!RepositionAndMapTrack(0))
2649  {
2650  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2651  Utilities->CallLogPop(1138);
2652  return(false);
2653  }
2654 // now perform the final assembly - FinalCall = true
2655  if(GiveMessages)
2656  {
2657  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2658  {
2659  Utilities->CallLogPop(1116);
2660  return(false);
2661  }
2662  }
2663  else
2664  {
2665  if(!LinkTrackNoMessages(2, true))
2666  {
2667  Utilities->CallLogPop(1132);
2668  return(false);
2669  }
2670  }
2671 // success
2672 
2673  PopulateLCVector(0);
2674  CheckGapMap(2); // test
2675  CheckMapAndTrack(3); // test
2676  CheckMapAndInactiveTrack(3); // test
2677  CheckLocationNameMultiMap(9); // test
2678  SetTrackFinished(true);
2679 
2680 // Build ContinuationNameMap
2681  std::pair<AnsiString, char>TempMapPair;
2682 
2683  ContinuationNameMap.clear();
2684  for(int x = 0; x < Track->TrackVectorSize(); x++)
2685  {
2686  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2687  {
2688  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2689  TempMapPair.second = 'x'; // unused
2690  ContinuationNameMap.insert(TempMapPair);
2691  }
2692  }
2693 
2694 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2695 //(don't report blue areas without track as these unlikely to be mistakes)
2696 
2697  if(TrackFinished)
2698  {
2699  AnsiString Name = "";
2700  typedef std::list<AnsiString> TNoPlatsList;
2701  TNoPlatsList::iterator NPLIt;
2702  TNoPlatsList NoPlatsList;
2703  typedef std::list<AnsiString> TLocNameList;
2704  TLocNameList LocNameList; //single entry for each name
2707  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2708  {
2709  LocNameList.push_back(LNMMIt->first);
2710  }
2711  LocNameList.sort();
2712  LocNameList.unique();
2713  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2714  {
2715  Name = *LNLIt;
2716  MMRange = LocationNameMultiMap.equal_range(Name);
2717  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2718  {
2719  continue;
2720  }
2721  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2722  {
2723  if((LNMMIt->second) < 0) //active track element
2724  {
2725  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2726  {
2727  break;
2728  }
2729  }
2730  else //inactive
2731  {
2732  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2733  {
2734  break;
2735  }
2736  }
2737  TempIt = MMRange.second;
2738  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2739  {
2740  NoPlatsList.push_back(Name);
2741  }
2742  }
2743  }
2744  if(!NoPlatsList.empty())
2745  {
2746  AnsiString NoPlatsAnsiList = "";
2747  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2748  {
2749  NoPlatsAnsiList += *NPLIt + '\n';
2750  }
2751  if(!NoPlatsMessageSent)
2752  {
2753  if(NoPlatsList.size() > 1)
2754  {
2755  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2756  }
2757  else
2758  {
2759  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2760  }
2761  NoPlatsMessageSent = true;
2762  }
2763  }
2764  }
2765  Utilities->CallLogPop(440);
2766  return(true);
2767 }
2768 
2769 // ---------------------------------------------------------------------------
2770 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2771 // unused - too time-consuming - double brute force search
2772 {
2773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2774  int NewHLoc, NewVLoc;
2775  bool ConnectionFoundFlag, LinkFoundFlag;
2776 
2777  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2778  {
2779  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2780  {
2781  if(TrackElementAt(1061, x).Link[y] <= 0)
2782  {
2783  continue; // no link
2784  }
2785  if(TrackElementAt(1062, x).Config[y] == End)
2786  {
2787  continue; // buffer or continuation
2788  }
2789  if(TrackElementAt(1063, x).Config[y] == Gap)
2790  {
2791  continue; // gap jump
2792  }
2793  // get required H & V for track element joining link 'y'
2794  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2795  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2796  // find track element if present
2797  ConnectionFoundFlag = false;
2798  for(unsigned int z = 0; z < TrackVector.size(); z++)
2799  {
2800 // if(TrackElementAt(5, z).TrackType == Platform)
2801 // continue; //skip platforms
2802  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2803  {
2804  ConnectionFoundFlag = true;
2805  // find connecting link in the newly found track element if there is one
2806  LinkFoundFlag = false;
2807  for(unsigned int a = 0; a < 4; a++)
2808  {
2809  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2810  {
2811  LinkFoundFlag = true;
2812  }
2813  }
2814  // if there isn't a corresponding link set the invert values for the offending element
2815  if(!LinkFoundFlag)
2816  {
2817  HLoc = TrackElementAt(1072, x).HLoc;
2818  VLoc = TrackElementAt(1073, x).VLoc;
2819  Utilities->CallLogPop(441);
2820  return(true);
2821  }
2822  break; // success, so break out of 'z' loop
2823  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2824 
2825  } // for z...
2826  // if there isn't a connection set the invert values for the offending element
2827  if(!ConnectionFoundFlag)
2828  {
2829  HLoc = TrackElementAt(1074, x).HLoc;
2830  VLoc = TrackElementAt(1075, x).VLoc;
2831  Utilities->CallLogPop(442);
2832  return(true);
2833  }
2834  } // for y....
2835  } // for x...
2836  Utilities->CallLogPop(443);
2837  return(false); // all OK
2838 }
2839 
2840 // ---------------------------------------------------------------------------
2841 
2842 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2843 {
2844  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2845  TrackElement.LogTrack(0));
2846  bool FoundFlag;
2847 
2848  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2849  if(FoundFlag)
2850  {
2851  TrackElement = TrackElementAt(1076, Position);
2852  }
2853  Utilities->CallLogPop(444);
2854  return(FoundFlag);
2855 }
2856 
2857 // ---------------------------------------------------------------------------
2858 
2860 {
2861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2862  if(NextTrackElementPtr >= TrackVector.end())
2863  {
2864  Utilities->CallLogPop(1336);
2865  return(false);
2866  }
2867  Next = *NextTrackElementPtr;
2869  Utilities->CallLogPop(1337);
2870  return(true);
2871 }
2872 
2873 // ---------------------------------------------------------------------------
2874 
2876 {
2877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2879  {
2880  Utilities->CallLogPop(1338);
2881  return(false);
2882  }
2883  Next = *NextTrackElementPtr;
2885  Utilities->CallLogPop(1339);
2886  return(true);
2887 }
2888 
2889 // ---------------------------------------------------------------------------
2890 
2891 int TTrack::NumberOfGaps(int Caller)
2892 
2893 {
2894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2895  int Count = 0;
2896 
2897  if(TrackVector.size() == 0)
2898  {
2899  Utilities->CallLogPop(1340);
2900  return(0);
2901  }
2902  for(unsigned int x = 0; x < TrackVector.size(); x++)
2903  {
2904  if(TrackElementAt(1077, x).TrackType == GapJump)
2905  {
2906  Count++;
2907  }
2908  }
2909  Utilities->CallLogPop(1341);
2910  return(Count);
2911 }
2912 
2913 // ---------------------------------------------------------------------------
2915 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2916 // returns true for any unset gaps
2917 {
2918  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2919  bool UnsetGaps = false;
2920 
2921  if(TrackVector.size() == 0)
2922  {
2923  Utilities->CallLogPop(445);
2924  return(false);
2925  }
2926  for(unsigned int x = 0; x < TrackVector.size(); x++)
2927  {
2928  if(TrackElementAt(1078, x).TrackType != GapJump)
2929  {
2930  for(unsigned int y = 0; y < 4; y++)
2931  {
2932  TrackElementAt(1079, x).Conn[y] = -1;
2933  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2934  }
2935  }
2936  else // GapJump
2937  {
2938 // int tempint = TrackElementAt(, x).Conn[0);
2939 
2940  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2941  {
2942  for(unsigned int y = 0; y < 4; y++)
2943  {
2944  TrackElementAt(1082, x).Conn[y] = -1;
2945  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2946  }
2947  UnsetGaps = true;
2948  continue; // to next 'x'
2949  }
2950  else // set, but may not have matching element, or that element may not be set
2951  {
2952  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2953  {
2954  TrackElementAt(1084, x).Conn[y] = -1;
2955  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2956  }
2957 
2958  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2959  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2960  {
2961  for(unsigned int y = 0; y < 4; y++)
2962  {
2963  TrackElementAt(1087, x).Conn[y] = -1;
2964  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2965  }
2966  UnsetGaps = true;
2967  continue; // to next 'x'
2968  }
2969 // here if gap connection is itself a GapJump
2970  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2971  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2972  // if not clear Conns & CLks & reset Lk[0]
2973  {
2974  for(unsigned int y = 0; y < 4; y++)
2975  {
2976  TrackElementAt(1090, x).Conn[y] = -1;
2977  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2978  }
2979  UnsetGaps = true;
2980  continue; // to next 'x'
2981  }
2982 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2983 // hence no more action needed on these Conns & CLks
2984  }
2985  } // else //gap jump
2986 
2987  } // for x...
2988  Utilities->CallLogPop(446);
2989  return(UnsetGaps);
2990 }
2991 
2992 // ---------------------------------------------------------------------------
2993 
2994 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2995 {
2996 // VecFile already open and its pointer at right place on calling
2997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2998  int TempInt;
2999 
3000  TrackClear(1);
3001 // load track elements
3002  int NumberOfActiveElements = 0;
3003 
3004  GraphicsFollow = false;
3005  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3006  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3007 
3008  if(MarkerString[MarkerString.Length()] == '1')
3009  {
3010  GraphicsFollow = true;
3011  }
3012  for(int x = 0; x < NumberOfActiveElements; x++)
3013  {
3014  VecFile >> TempInt; // TrackVectorNumber, not used
3015  VecFile >> TempInt; // SpeedTag
3016  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3017  VecFile >> TempInt;
3018  TrackElement.HLoc = TempInt;
3019  VecFile >> TempInt;
3020  TrackElement.VLoc = TempInt;
3021  if(TrackElement.TrackType == GapJump)
3022  {
3023  VecFile >> TempInt;
3024  TrackElement.ConnLinkPos[0] = TempInt;
3025  VecFile >> TempInt;
3026  TrackElement.Conn[0] = TempInt;
3027  }
3028  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3029  {
3030  VecFile >> TempInt;
3031  TrackElement.Attribute = TempInt;
3032  }
3033  if(TrackElement.TrackType == SignalPost)
3034  {
3035  VecFile >> TempInt;
3036  if(TempInt == 0)
3037  {
3038  TrackElement.CallingOnSet = false;
3039  }
3040  else
3041  {
3042  TrackElement.CallingOnSet = true;
3043  }
3044  }
3045  VecFile >> TempInt;
3046  TrackElement.Length01 = TempInt;
3047  VecFile >> TempInt;
3048  TrackElement.Length23 = TempInt;
3049  VecFile >> TempInt;
3050  if((TempInt != -1) && (TempInt < 10))
3051  {
3052  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3053  }
3054  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3055  {
3056  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3057  }
3058  TrackElement.SpeedLimit01 = TempInt;
3059  VecFile >> TempInt;
3060  if((TempInt != -1) && (TempInt < 10))
3061  {
3062  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3063  }
3064  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3065  {
3066  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3067  }
3068  TrackElement.SpeedLimit23 = TempInt;
3069 
3070  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3071  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3072  SetElementID(0, TrackElement);
3073  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3074 // new for v0.6
3075  if(TrackElement.TrackType == SignalPost)
3076  {
3077  if(Marker[1] == '3')
3078  {
3079  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3080  }
3081  else if(Marker[1] == '2')
3082  {
3083  TrackElement.SigAspect = TTrackElement::TwoAspect;
3084  }
3085  else if(Marker[1] == 'G')
3086  {
3087  TrackElement.SigAspect = TTrackElement::GroundSignal;
3088  }
3089  else
3090  {
3091  TrackElement.SigAspect = TTrackElement::FourAspect;
3092  }
3093  }
3094  if(TrackElement.SpeedTag != 0)
3095  {
3096  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3097  }
3098  }
3099  int NumberOfInactiveElements = 0;
3100 
3101  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3102  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3103  for(int x = 0; x < NumberOfInactiveElements; x++)
3104  {
3105  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3106  VecFile >> TempInt; // SpeedTag
3107  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3108  VecFile >> TempInt;
3109  TrackElement.HLoc = TempInt;
3110  VecFile >> TempInt;
3111  TrackElement.VLoc = TempInt;
3112  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3113  SetElementID(3, TrackElement);
3114  TrackPush(9, TrackElement);
3115  Utilities->LoadFileString(VecFile); // marker
3116  }
3117  bool LocError = false; // needed for TryToConnectTrack but not used
3118  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3119 
3120  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3121  {
3122  SetTrackFinished(true);
3123  }
3124  else
3125  {
3126  SetTrackFinished(false);
3127  }
3128 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3129 // CheckMapAndInactiveTrack(8);
3130 // CheckLocationNameMultiMap(10);
3131  Utilities->CallLogPop(448);
3132 }
3133 
3134 // ---------------------------------------------------------------------------
3135 
3136 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3137 {
3138 // VecFile already open and its pointer at right place on calling
3139  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3140 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3141 // & load into UserGraphicItem then store in UserGraphicVector
3142  UserGraphicVector.clear();
3143  TUserGraphicItem UGI;
3144  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3145 
3146  for(int x = 0; x < NumberOfGraphics; x++)
3147  {
3148  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3149  UGI.HPos = Utilities->LoadFileInt(VecFile);
3150  UGI.VPos = Utilities->LoadFileInt(VecFile);
3151  UGI.Width = 0; // provisional value
3152  UGI.Height = 0; // provisional value
3153  UGI.UserGraphic = NULL; // provisional value
3154  UserGraphicVector.push_back(UGI);
3155  }
3156 // now load the map & set Width, Height & TPicture*
3157  bool FileError = false;
3158 
3159  for(int x = 0; x < NumberOfGraphics; x++)
3160  {
3161  if(FileError)
3162  {
3163  break; // otherwise keeps going round the loop
3164  }
3165  UGI = UserGraphicVectorAt(0, x);
3166  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3167  {
3168  try
3169  {
3170 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3171  UGME.first = UGI.FileName;
3172  UGME.second = new TPicture;
3173  UGME.second->LoadFromFile(UGME.first); // errors caught below
3174  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3175  {
3176  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3177  }
3178  UGI.UserGraphic = UGME.second;
3179  UGI.Width = UGI.UserGraphic->Width;
3180  UGI.Height = UGI.UserGraphic->Height;
3181  UserGraphicVectorAt(1, x) = UGI;
3182  }
3183  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3184  {
3185  //message already sent in CheckUserGraphics
3186  FileError = true;
3187  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3188  if(!UserGraphicMap.empty())
3189  {
3190  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3191  {
3192  delete UGMIt->second;
3193  }
3194  UserGraphicMap.clear();
3195  }
3196  }
3197  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3198  {
3199  //message already sent in CheckUserGraphics
3200  FileError = true;
3201  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3202  if(!UserGraphicMap.empty())
3203  {
3204  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3205  {
3206  delete UGMIt->second;
3207  }
3208  UserGraphicMap.clear();
3209  }
3210  }
3211  }
3212  else
3213  {
3214  bool FoundInMap = false;
3215  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3216  {
3217  if(UGI.FileName == UGMIt->first) // already exists in map
3218  {
3219  UGI.UserGraphic = UGMIt->second;
3220  UGI.Width = UGI.UserGraphic->Width;
3221  UGI.Height = UGI.UserGraphic->Height;
3222  UserGraphicVectorAt(2, x) = UGI;
3223  FoundInMap = true;
3224  break;
3225  }
3226  }
3227  if(!FoundInMap)
3228  {
3229  try
3230  {
3232  UGME.first = UGI.FileName;
3233  UGME.second = new TPicture;
3234  UGME.second->LoadFromFile(UGME.first); // errors caught below
3235  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3236  {
3237  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3238  }
3239  UGI.UserGraphic = UGME.second;
3240  UGI.Width = UGI.UserGraphic->Width;
3241  UGI.Height = UGI.UserGraphic->Height;
3242  UserGraphicVectorAt(3, x) = UGI;
3243  }
3244  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3245  {
3246  //message already sent in CheckUserGraphics
3247  FileError = true;
3248  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3249  if(!UserGraphicMap.empty())
3250  {
3251  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3252  {
3253  delete UGMIt->second;
3254  }
3255  UserGraphicMap.clear();
3256  }
3257  }
3258  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3259  {
3260  //message already sent in CheckUserGraphics
3261  FileError = true;
3262  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3263  if(!UserGraphicMap.empty())
3264  {
3265  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3266  {
3267  delete UGMIt->second;
3268  }
3269  UserGraphicMap.clear();
3270  }
3271  }
3272  }
3273  }
3274  }
3275  Utilities->CallLogPop(2167);
3276 }
3277 
3278 // ---------------------------------------------------------------------------
3279 
3280 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3281 {
3282 // VecFile already open and its pointer at right place on calling
3283 // if GraphicsFollow true, then save Marker as **Active elements**1
3284 // save trackfinished flag
3285  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3286  TTrackElement TrackElement, InactiveTrackElement;
3287 
3288 // save track elements
3289  Utilities->SaveFileInt(VecFile, TrackVector.size());
3290  if(GraphicsFollow)
3291  {
3292  VecFile << "**Active elements**1" << '\0' << '\n';
3293  }
3294  else
3295  {
3296  VecFile << "**Active elements**" << '\0' << '\n';
3297  }
3298  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3299  {
3300  TrackElement = TrackElementAt(1092, x);
3301  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3302  VecFile << TrackElement.SpeedTag << '\n';
3303  VecFile << TrackElement.HLoc << '\n';
3304  VecFile << TrackElement.VLoc << '\n';
3305  if(TrackElement.TrackType == GapJump)
3306  {
3307  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3308  VecFile << TrackElement.Conn[0] << '\n';
3309  }
3310  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3311  {
3312  VecFile << TrackElement.Attribute << '\n';
3313  }
3314  if(TrackElement.TrackType == SignalPost)
3315  {
3316  if(TrackElement.CallingOnSet)
3317  {
3318  VecFile << int(1) << '\n';
3319  }
3320  else
3321  {
3322  VecFile << int(0) << '\n';
3323  }
3324  }
3325  VecFile << TrackElement.Length01 << '\n';
3326  VecFile << TrackElement.Length23 << '\n';
3327  VecFile << TrackElement.SpeedLimit01 << '\n';
3328  VecFile << TrackElement.SpeedLimit23 << '\n';
3329  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3330  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3331 // new for v0.6
3332  if(TrackElement.TrackType == SignalPost)
3333  {
3334  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3335  {
3336  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3337  }
3338  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3339  {
3340  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3341  }
3342  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3343  {
3344  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3345  }
3346  else // 4 aspect
3347  {
3348  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3349  }
3350  }
3351  else
3352  {
3353  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3354  }
3355  }
3356 
3357  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3358  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3359  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3360  {
3361  InactiveTrackElement = InactiveTrackElementAt(136, x);
3362  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3363  VecFile << InactiveTrackElement.SpeedTag << '\n';
3364  VecFile << InactiveTrackElement.HLoc << '\n';
3365  VecFile << InactiveTrackElement.VLoc << '\n';
3366  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3367  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3368  }
3369  Utilities->CallLogPop(449);
3370 }
3371 
3372 // ---------------------------------------------------------------------------
3373 
3374 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3375 {
3376 // VecFile already open and its pointer at right place on calling
3377 // check trackfinished flag
3378 // inactive elements follow immediately after active elements, no need to check for a marker between them
3379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3380  int TempInt;
3381 
3382  GraphicsFollow = false;
3383  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3384  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3385  {
3386  Utilities->CallLogPop(1513);
3387  return(false);
3388  }
3389 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3390  AnsiString MarkerString;
3391 
3392  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3393  {
3394  Utilities->CallLogPop(1758);
3395  return(false);
3396  }
3397  if(MarkerString[MarkerString.Length()] == '1')
3398  {
3399  GraphicsFollow = true;
3400  }
3401  for(int x = 0; x < NumberOfActiveElements; x++)
3402  {
3403  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3404  {
3405  Utilities->CallLogPop(1759);
3406  return(false);
3407  }
3408  VecFile >> TempInt;
3409  int SpeedTag = TempInt;
3410  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3411  {
3412  Utilities->CallLogPop(1514);
3413  return(false);
3414  }
3415  VecFile >> TempInt;
3416  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3417  {
3418  Utilities->CallLogPop(1495);
3419  return(false);
3420  }
3421  VecFile >> TempInt;
3422  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3423  {
3424  Utilities->CallLogPop(1497);
3425  return(false);
3426  }
3427  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3428  {
3429  VecFile >> TempInt;
3430  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3431  {
3432  Utilities->CallLogPop(1499);
3433  return(false);
3434  }
3435  VecFile >> TempInt;
3436  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3437  {
3438  Utilities->CallLogPop(1500);
3439  return(false);
3440  }
3441  }
3442  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3443  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3444  {
3445  VecFile >> TempInt;
3446  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3447  {
3448  Utilities->CallLogPop(1502);
3449  return(false);
3450  }
3451  }
3452  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3453  {
3454  VecFile >> TempInt;
3455  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3456  {
3457  Utilities->CallLogPop(1155);
3458  return(false);
3459  }
3460  }
3461  VecFile >> TempInt;
3462  if((TempInt < -1) || (TempInt > 999999)) // Length01
3463  {
3464  Utilities->CallLogPop(1503);
3465  return(false);
3466  }
3467  VecFile >> TempInt;
3468  if((TempInt < -1) || (TempInt > 999999)) // Length23
3469  {
3470  Utilities->CallLogPop(1504);
3471  return(false);
3472  }
3473  VecFile >> TempInt;
3474  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3475  {
3476  Utilities->CallLogPop(1505);
3477  return(false);
3478  }
3479  VecFile >> TempInt;
3480  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3481  {
3482  Utilities->CallLogPop(1506);
3483  return(false);
3484  }
3485  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3486  {
3487  Utilities->CallLogPop(1142);
3488  return(false); // LocationName
3489  }
3490  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3491  {
3492  Utilities->CallLogPop(1143);
3493  return(false); // ActiveTrackElementName
3494  }
3495  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3496  {
3497  Utilities->CallLogPop(1787);
3498  return(false); // marker
3499  }
3500  }
3501  int NumberOfInactiveElements = 0;
3502 
3503  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3504  if(NumberOfInactiveElements < 0) // No of active elements
3505  {
3506  Utilities->CallLogPop(1493);
3507  return(false);
3508  }
3509  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3510  {
3511  Utilities->CallLogPop(1764);
3512  return(false); // **Inactive elements** marker
3513  }
3514  for(int x = 0; x < NumberOfInactiveElements; x++)
3515  {
3516  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3517  {
3518  Utilities->CallLogPop(1765);
3519  return(false);
3520  }
3521  VecFile >> TempInt;
3522  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3523  {
3524  Utilities->CallLogPop(1494);
3525  return(false);
3526  }
3527  VecFile >> TempInt;
3528  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3529  {
3530  Utilities->CallLogPop(1496);
3531  return(false);
3532  }
3533  VecFile >> TempInt;
3534  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3535  {
3536  Utilities->CallLogPop(1498);
3537  return(false);
3538  }
3539  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3540  {
3541  Utilities->CallLogPop(1144);
3542  return(false); // LocationName
3543  }
3544  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3545  {
3546  Utilities->CallLogPop(1788);
3547  return(false); // marker
3548  }
3549  }
3550  Utilities->CallLogPop(1507);
3551  return(true);
3552 }
3553 
3554 // ---------------------------------------------------------------------------
3555 
3556 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3557 {
3558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3559  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3560 
3561  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3562  {
3563  Utilities->CallLogPop(2168);
3564  return(false);
3565  }
3566  // filename in Graphics folder, then HPos, then VPos
3567  AnsiString FileName = "", TempStr = "";
3568 
3569  for(int x = 0; x < NumberOfGraphics; x++)
3570  {
3571  TPicture *TempPicture = new TPicture;
3572  try
3573  {
3574  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3575  {
3576  Utilities->CallLogPop(2169);
3577  delete TempPicture;
3578  return(false);
3579  }
3580  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3581  delete TempPicture;
3582  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3583  {
3584  Utilities->CallLogPop(2170);
3585  return(false);
3586  }
3587  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3588  {
3589  Utilities->CallLogPop(2171);
3590  return(false);
3591  }
3592  }
3593  catch(const EInvalidGraphic &e) //non error catch
3594  {
3595  //move file pointer to end of graphic section for later checks in session files
3596  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3597  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3598  for(int y = x + 1; y < NumberOfGraphics; y++)
3599  {
3600  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3601  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3602  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3603  }
3604  ShowMessage(FileName +
3605  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3606  Utilities->CallLogPop(2172);
3607  delete TempPicture;
3608  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3609  }
3610  catch(const Exception &e) //non error catch
3611  {
3612  //move file pointer to end of graphic section for later checks in session files
3613  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3614  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3615  for(int y = x + 1; y < NumberOfGraphics; y++)
3616  {
3617  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3618  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3619  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3620  }
3621  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3622  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3623  Utilities->CallLogPop(2173);
3624  delete TempPicture;
3625  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3626  }
3627  }
3628  Utilities->CallLogPop(2174);
3629  return(true);
3630 }
3631 
3632 // ---------------------------------------------------------------------------
3633 
3634 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3635 {
3636  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3637  int VecSize = Track->BarriersDownVector.size();
3638 
3639  Utilities->SaveFileInt(OutFile, VecSize);
3640  for(int x = 0; x < VecSize; x++)
3641  {
3643  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3644  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3645  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3646  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3647  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3648  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3649  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3650  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3651  }
3652  Utilities->CallLogPop(1963);
3653 }
3654 
3655 // ---------------------------------------------------------------------------
3656 
3657 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3658 {
3659  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3660  int VecSize = Track->ChangingLCVector.size();
3661 
3662  Utilities->SaveFileInt(OutFile, VecSize);
3663  for(int x = 0; x < VecSize; x++)
3664  {
3666  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3667  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3668  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3669  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3670  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3671  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3672  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3673  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3674  }
3675  Utilities->CallLogPop(1980);
3676 }
3677 
3678 // ---------------------------------------------------------------------------
3679 
3680 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3681 {
3682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3683  int VecSize = Utilities->LoadFileInt(VecFile);
3684 
3685  for(int x = 0; x < VecSize; x++)
3686  {
3687  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3688  {
3689  Utilities->CallLogPop(1970);
3690  return(false);
3691  }
3692  if(!Utilities->CheckFileBool(VecFile))
3693  {
3694  Utilities->CallLogPop(1971);
3695  return(false);
3696  }
3697  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3698  {
3699  Utilities->CallLogPop(1972);
3700  return(false);
3701  }
3702  if(!Utilities->CheckFileDouble(VecFile))
3703  {
3704  Utilities->CallLogPop(1973);
3705  return(false);
3706  }
3707  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3708  {
3709  Utilities->CallLogPop(1974);
3710  return(false);
3711  }
3712  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3713  {
3714  Utilities->CallLogPop(1975);
3715  return(false);
3716  }
3717  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3718  {
3719  Utilities->CallLogPop(1976);
3720  return(false);
3721  }
3722  if(!Utilities->CheckFileDouble(VecFile))
3723  {
3724  Utilities->CallLogPop(1977);
3725  return(false);
3726  }
3727  }
3728  Utilities->CallLogPop(1978);
3729  return(true);
3730 }
3731 
3732 // ---------------------------------------------------------------------------
3733 
3734 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3735 {
3736  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3737  int VecSize = Utilities->LoadFileInt(VecFile);
3738 
3739  for(int x = 0; x < VecSize; x++)
3740  {
3741  TActiveLevelCrossing TALC;
3742  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3743  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3744  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3745  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3746  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3747  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3748  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3749  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3750  BarriersDownVector.push_back(TALC);
3751  }
3752  Utilities->CallLogPop(1979);
3753 }
3754 
3755 // ---------------------------------------------------------------------------
3756 
3757 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3758 /*
3759  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3760  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3761  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3762 */
3763 {
3764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3765  TTrackElement Next;
3766 
3767 // Disp->ClearDisplay();
3769  while(ReturnNextInactiveTrackElement(0, Next))
3770  {
3771  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3772  {
3773  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3774  {
3775  // only plot if on screen, to save time
3776  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3778  {
3779  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3780  }
3781  }
3782  }
3783  }
3784 
3785  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3786 
3787  NextTrackElementPtr = TrackVector.begin();
3788  while(ReturnNextTrackElement(0, Next))
3789  {
3790  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3791  {
3792  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3794  {
3795  if(Next.TrackType == Points)
3796  {
3797  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3798  }
3799  else if(Next.TrackType == SignalPost)
3800  {
3801  PlotSignal(9, Next, Disp);
3802  }
3803  else if(Next.TrackType == GapJump)
3804  {
3805  PlotGap(0, Next, Disp);
3806  }
3807  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3808  {
3809  PlotContinuation(0, Next, Disp);
3810  }
3811  else
3812  {
3813  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3814  }
3815  }
3816  }
3817  }
3818 
3819  if(BothPointFilletsAndBasicLCs)
3820  {
3822  while(ReturnNextInactiveTrackElement(4, Next))
3823  {
3824  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3825  {
3826  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3827  {
3828  // only plot if on screen, to save time, & OK as plotting one by one here
3829  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3831  {
3832  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3833  {
3834  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3835  }
3836  else
3837  {
3838  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3839  }
3840  }
3841  }
3842  }
3843  }
3844  }
3845  Disp->Update();
3846  Utilities->CallLogPop(468);
3847 }
3848 
3849 // ---------------------------------------------------------------------------
3850 
3851 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3852 {
3853  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3854  if(UserGraphicVector.empty())
3855  {
3856  Utilities->CallLogPop(2175);
3857  return;
3858  }
3859  TUserGraphicItem UGI;
3860 
3861  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3862  {
3863  UGI = UserGraphicVectorAt(4, x);
3864  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3865  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3866  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3867  {
3868  Disp->PlotAndAddUserGraphic(0, UGI);
3869  }
3870  }
3871  Disp->Update();
3872  Utilities->CallLogPop(2176);
3873 }
3874 
3875 // ---------------------------------------------------------------------------
3876 
3877 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3878 /*
3879  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3880 */
3881 {
3882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3883 // need to change graphics back to black on white if have a dark background
3884  TColor OldTransparentColour = Utilities->clTransparent;
3885 
3887  {
3888  Utilities->clTransparent = TColor(0xFFFFFF); // white
3891  }
3892  TTrackElement Next;
3893 
3894  Bitmap->Canvas->CopyMode = cmSrcCopy;
3896  Graphics::TBitmap *GraphicOutput;
3897 
3898  while(ReturnNextInactiveTrackElement(2, Next))
3899  {
3900  GraphicOutput = Next.GraphicPtr;
3901  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3902  {
3903  if(Next.LocationName == "") // plot as named or unnamed (striped)
3904  {
3905  // default is not striped
3906  switch(Next.SpeedTag)
3907  {
3908  case 76: // t platform
3909  GraphicOutput = RailGraphics->gl76Striped;
3910  break;
3911 
3912  case 77: // h platform
3913  GraphicOutput = RailGraphics->bm77Striped;
3914  break;
3915 
3916  case 78: // v platform
3917  GraphicOutput = RailGraphics->bm78Striped;
3918  break;
3919 
3920  case 79: // r platform
3921  GraphicOutput = RailGraphics->gl79Striped;
3922  break;
3923 
3924  case 96: // concourse
3925  GraphicOutput = RailGraphics->ConcourseStriped;
3926  break;
3927 
3928  case 129: // v footbridge
3929  GraphicOutput = RailGraphics->gl129Striped;
3930  break;
3931 
3932  case 130: // h footbridge
3933  GraphicOutput = RailGraphics->gl130Striped;
3934  break;
3935 
3936  case 131: // non-station named loc
3937  GraphicOutput = RailGraphics->bmNameStriped;
3938  break;
3939 
3940  case 145: // v underpass
3941  GraphicOutput = RailGraphics->gl145Striped;
3942  break;
3943 
3944  case 146: // h underpass
3945  GraphicOutput = RailGraphics->gl146Striped;
3946  break;
3947 
3948  default:
3949  GraphicOutput = Next.GraphicPtr;
3950  break;
3951  }
3952  }
3953  if(Next.SpeedTag == 144) // level crossing
3954  {
3955  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3956  {
3957  GraphicOutput = RailGraphics->LCBothVer;
3958  }
3959  else
3960  {
3961  GraphicOutput = RailGraphics->LCBothHor;
3962  }
3963  }
3964  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3965  }
3966  }
3967 
3968  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3969 
3970 
3971  NextTrackElementPtr = TrackVector.begin();
3972  while(ReturnNextTrackElement(2, Next))
3973  {
3974  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3975  {
3976  if(Next.TrackType == Points) // plot both fillets
3977  {
3978  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3979  if(Next.SpeedTag < 28)
3980  {
3981  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3983  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3985  }
3986  else if(Next.SpeedTag < 132)
3987  {
3988  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3989  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3990  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3991  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3992  }
3993  else
3994  {
3995  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3996  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3997  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3998  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3999  }
4000  }
4001  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4002  {
4003  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4004  {
4005  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4006  }
4007  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4008  {
4009  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4010  }
4011  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4012  {
4013  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4014  }
4015  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4016  {
4017  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4018  }
4019  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4020  {
4021  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4022  }
4023  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4024  {
4025  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4026  }
4027  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4028  {
4029  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4030  }
4031  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4032  {
4033  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4034  }
4035  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4036  {
4037  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4038  }
4039  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4040  {
4041  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4042  }
4043  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4044  {
4045  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4046  }
4047  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4048  {
4049  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4050  }
4051  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4052  {
4053  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4054  }
4055  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4056  {
4057  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4058  }
4059  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4060  {
4061  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4062  }
4063  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4064  {
4065  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4066  }
4067  }
4068  // below added for version 0.6, only stop signals to be drawn
4069  else if(Next.TrackType == SignalPost)
4070  {
4071  for(int x = 0; x < 40; x++)
4072  {
4073  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4074  {
4075  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4076  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4077  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4078  int HOffset = 0;
4079  if(Next.SpeedTag > 73)
4080  {
4081  HOffset = 5;
4082  }
4083  else if(Next.SpeedTag == 71)
4084  {
4085  HOffset = 9;
4086  }
4087  int VOffset = 0;
4088  if(Next.SpeedTag == 69)
4089  {
4090  VOffset = 9;
4091  }
4092  else if(Next.SpeedTag == 72)
4093  {
4094  VOffset = 5;
4095  }
4096  else if(Next.SpeedTag == 74)
4097  {
4098  VOffset = 5;
4099  }
4100  Graphics::TBitmap *GraphicPtr;
4101  if(Next.SpeedTag > 71)
4102  {
4103  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4104  }
4105  else if(Next.SpeedTag < 70)
4106  {
4107  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4108  }
4109  else
4110  {
4111  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4112  }
4113  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4114  // plot special signal platform if present
4115  Graphics::TBitmap* SignalPlatformGraphic;
4116  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4117  {
4118  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4119  }
4120  // now plot signal (double yellow overwrites most of signal platform if present)
4121  // below amended for version 0.6
4123  {
4124  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4125  }
4126  else if(Next.SigAspect == TTrackElement::TwoAspect)
4127  {
4128  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4129  }
4130  else if(Next.SigAspect == TTrackElement::GroundSignal)
4131  {
4132  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4133  }
4134  else // 4 aspect
4135  {
4136  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4137  }
4138  break;
4139  }
4140  }
4141  }
4142  else
4143  {
4144  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4145  }
4146  }
4147  }
4148  if(OldTransparentColour != clB5G5R5)
4149  {
4150  Utilities->clTransparent = OldTransparentColour; // restore
4153  }
4154  Utilities->CallLogPop(1533);
4155 }
4156 
4157 // ---------------------------------------------------------------------------
4158 
4159 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4160 {
4161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4162  if(UserGraphicVector.empty())
4163  {
4164  Utilities->CallLogPop(2192);
4165  return;
4166  }
4167  else
4168  {
4169  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4170  {
4171  Bitmap->Canvas->CopyMode = cmSrcCopy;
4172  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4173  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4174  }
4175  }
4176  Utilities->CallLogPop(2193);
4177 }
4178 
4179 // ---------------------------------------------------------------------------
4180 
4181 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4182 /*
4183  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4184  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4185 */
4186 {
4187  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4188 // need to change graphics back to black on white if have a dark background
4189  TColor OldTransparentColour = Utilities->clTransparent;
4190 
4192  {
4193  Utilities->clTransparent = TColor(0xFFFFFF); // white
4196  }
4197  TTrackElement Next;
4198 
4199  Bitmap->Canvas->CopyMode = cmSrcCopy;
4201  Graphics::TBitmap *GraphicOutput;
4202 
4203  while(ReturnNextInactiveTrackElement(3, Next))
4204  {
4205  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4206  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4207  {
4208  if(Next.SpeedTag == 144) // level crossing
4209  {
4210  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4211  if(BaseElement == 1) // hor element
4212  {
4213  if(Next.Attribute == 1) // open to trains
4214  {
4215  GraphicOutput = RailGraphics->LCBothHor;
4216  }
4217  else // plot as closed to trains if in any other state
4218  {
4219  GraphicOutput = RailGraphics->LCBothVer;
4220  }
4221  }
4222  else // vert element
4223  {
4224  if(Next.Attribute == 1) // open to trains
4225  {
4226  GraphicOutput = RailGraphics->LCBothVer;
4227  }
4228  else // plot as closed to trains if in any other state
4229  {
4230  GraphicOutput = RailGraphics->LCBothHor;
4231  }
4232  }
4233  }
4234  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4235  }
4236  }
4237 
4238  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4239 
4240  NextTrackElementPtr = TrackVector.begin();
4241  while(ReturnNextTrackElement(3, Next))
4242  {
4243  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4244  {
4245  if(Next.TrackType == Points) // plot active fillet
4246  {
4247  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4248  if(Next.SpeedTag < 28)
4249  {
4250  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4252  }
4253  else if(Next.SpeedTag < 132)
4254  {
4255  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4257  }
4258  else
4259  {
4260  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4262  }
4263  if(Next.Failed) //added at v2.13.0
4264  {
4265  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4267  }
4268 
4269  }
4270  else if(Next.TrackType == GapJump) // plot as connected
4271  {
4272  if(Next.SpeedTag == 88)
4273  {
4274  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4275  }
4276  else if(Next.SpeedTag == 89)
4277  {
4278  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4279  }
4280  else if(Next.SpeedTag == 90)
4281  {
4282  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4283  }
4284  else if(Next.SpeedTag == 91)
4285  {
4286  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4287  }
4288  else if(Next.SpeedTag == 92)
4289  {
4290  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4291  }
4292  else if(Next.SpeedTag == 93)
4293  {
4294  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4295  }
4296  else if(Next.SpeedTag == 94)
4297  {
4298  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4299  }
4300  else if(Next.SpeedTag == 95)
4301  {
4302  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4303  }
4304  }
4305  else if(Next.TrackType == SignalPost) //plot in correct colour
4306  {
4307  for(int x = 0; x < 40; x++)
4308  {
4309  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4310  {
4311  //plot blank first, then plot platform if present - (always not striped for operating railway)
4312  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4313  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4314  int HOffset = 0;
4315  if(Next.SpeedTag > 73)
4316  {
4317  HOffset = 5;
4318  }
4319  else if(Next.SpeedTag == 71)
4320  {
4321  HOffset = 9;
4322  }
4323  int VOffset = 0;
4324  if(Next.SpeedTag == 69)
4325  {
4326  VOffset = 9;
4327  }
4328  else if(Next.SpeedTag == 72)
4329  {
4330  VOffset = 5;
4331  }
4332  else if(Next.SpeedTag == 74)
4333  {
4334  VOffset = 5;
4335  }
4336  Graphics::TBitmap *GraphicPtr;
4337  if(Next.SpeedTag > 71)
4338  {
4339  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4340  }
4341  else if(Next.SpeedTag < 70)
4342  {
4343  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4344  }
4345  else
4346  {
4347  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4348  }
4349  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4350  // plot special signal platform if present
4351  Graphics::TBitmap* SignalPlatformGraphic;
4352  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4353  {
4354  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4355  }
4356  if(!Next.Failed)
4357  {
4358  // now plot signal (double yellow overwrites most of signal platform if present)
4359  // below amended for version 0.6
4361  {
4362  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4363  }
4364  else if(Next.SigAspect == TTrackElement::TwoAspect)
4365  {
4366  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4367  }
4368  else if(Next.SigAspect == TTrackElement::GroundSignal)
4369  {
4370  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4371  }
4372  else // 4 aspect
4373  {
4374  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4375  }
4376  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4377  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4378  {
4379  if(Next.SpeedTag == 68)
4380  {
4381  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4382  }
4383  if(Next.SpeedTag == 69)
4384  {
4385  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4386  }
4387  if(Next.SpeedTag == 70)
4388  {
4389  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4390  }
4391  if(Next.SpeedTag == 71)
4392  {
4393  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4394  }
4395  if(Next.SpeedTag == 72)
4396  {
4397  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4398  }
4399  if(Next.SpeedTag == 73)
4400  {
4401  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4402  }
4403  if(Next.SpeedTag == 74)
4404  {
4405  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4406  }
4407  if(Next.SpeedTag == 75)
4408  {
4409  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4410  }
4411  }
4412  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4413  {
4414  for(int x = 0; x < 40; x++)
4415  {
4416  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4417  {
4418  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4419  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4420  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4421  // plot special signal platform if present
4422  Graphics::TBitmap* SignalPlatformGraphic;
4423  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4424  {
4425  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4426  }
4427  // now plot signal
4428  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4429  break;
4430  }
4431  }
4432  }
4433  break;
4434  }
4435  else //added at v2.13.0
4436  {
4438  {
4439  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4440  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4441  }
4442  else
4443  {
4444  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4445  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4446  }
4447  break;
4448  }
4449  }
4450  }
4451  }
4452  else
4453  {
4454  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4455  if(Next.Failed) //added at v2.13.0
4456  {
4457  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4459  }
4460  }
4461  }
4462  }
4463  if(OldTransparentColour != clB5G5R5)
4464  {
4465  Utilities->clTransparent = OldTransparentColour; // restore
4468  }
4469  Utilities->CallLogPop(1701);
4470 }
4471 
4472 // ---------------------------------------------------------------------------
4473 
4474 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4475 {
4476  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4477  for(unsigned int x = 0; x < TrackVector.size(); x++)
4478  {
4479  if(TrackElementAt(1093, x).TrackType == GapJump)
4480  {
4481  if(TrackElementAt(1094, x).Conn[0] > -1)
4482  {
4483  continue; // to next 'x' value as this element has already been set
4484  }
4485  // here if identify a GapJump element not yet set
4486  GapPos = x;
4487  GapHLoc = TrackElementAt(1095, x).HLoc;
4488  GapVLoc = TrackElementAt(1096, x).VLoc;
4489  // highlight it
4491  Utilities->CallLogPop(469);
4492  return(true);
4493  }
4494  }
4495  Utilities->CallLogPop(470);
4496  return(false);
4497 }
4498 
4499 // ---------------------------------------------------------------------------
4500 
4501 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4502 {
4503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4504  AnsiString(VLoc));
4505  int Position;
4506  TTrackElement TrackElement;
4507 
4508  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4509  {
4510  Utilities->CallLogPop(471);
4511  return(false); // not found
4512  }
4513  if(TrackElement.TrackType != GapJump)
4514  {
4515  Utilities->CallLogPop(472);
4516  return(false); // found something but not a gap
4517  }
4518  if(Position == GapPos)
4519  {
4520  Utilities->CallLogPop(473);
4521  return(false); // selected original gap
4522  }
4523  if(TrackElementAt(1097, Position).Conn[0] != -1)
4524  {
4525  Utilities->CallLogPop(474);
4526  return(false); // already selected
4527  }
4528  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4529  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4530  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4531  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4532 // now highlight the selected location
4533  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4534  Utilities->CallLogPop(475);
4535  return(true);
4536 }
4537 
4538 // ---------------------------------------------------------------------------
4539 
4540 bool TTrack::GapsUnset(int Caller)
4541 // returns true if there are gaps and any are unset
4542 {
4543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4544  if(TrackVector.size() == 0)
4545  {
4546  Utilities->CallLogPop(476);
4547  return(false);
4548  }
4549  for(unsigned int x = 0; x < TrackVector.size(); x++)
4550  {
4551  if(TrackElementAt(1102, x).TrackType == GapJump)
4552  {
4553  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4554  {
4555  Utilities->CallLogPop(477);
4556  return(true);
4557  }
4558  else // set, but may not have matching element, or that element may not be set
4559  {
4560  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4561  // check that the element pointed to by the gap link is a GapJump
4562  {
4563  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4564  Utilities->CallLogPop(1137);
4565  return(false);
4566  }
4567 // here if gap connection is itself a GapJump
4568  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4569  // check that the element pointed to by the gap link is a GapJump & that its gap link
4570  // points back to 'x'
4571  {
4572  Utilities->CallLogPop(478);
4573  return(true);
4574  }
4575 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4576  }
4577  } // if(TrackElementAt(, x).TrackType == GapJump)
4578 
4579  } // for x...
4580  Utilities->CallLogPop(479);
4581  return(false);
4582 }
4583 
4584 // ---------------------------------------------------------------------------
4585 
4586 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4587 {
4588  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4589  for(unsigned int x = 0; x < TrackVector.size(); x++)
4590  {
4591  if(TrackElementAt(1110, x).TrackType == GapJump)
4592  {
4593  Utilities->CallLogPop(1105);
4594  return(false);
4595  }
4596  }
4597  Utilities->CallLogPop(1106);
4598  return(true);
4599 }
4600 
4601 // ---------------------------------------------------------------------------
4602 
4603 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4604 {
4605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4606  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4607  {
4608  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4609  {
4610  Utilities->CallLogPop(1107);
4611  return(false);
4612  }
4613  }
4614  for(unsigned int x = 0; x < TrackVector.size(); x++)
4615  {
4616  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4617  {
4618  Utilities->CallLogPop(1108);
4619  return(false);
4620  }
4621  }
4622  Utilities->CallLogPop(1109);
4623  return(true);
4624 }
4625 
4626 // ---------------------------------------------------------------------------
4627 
4629 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4630 // returns false otherwise or if there are no NamedLocationElements
4631 {
4632  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4633  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4634  {
4635  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4636  {
4637  if(InactiveTrackElementAt(139, x).LocationName == "")
4638  {
4639  Utilities->CallLogPop(1110);
4640  return(true);
4641  }
4642  }
4643  }
4644  for(unsigned int x = 0; x < TrackVector.size(); x++)
4645  {
4646  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4647  {
4648  if(TrackElementAt(1113, x).LocationName == "")
4649  {
4650  Utilities->CallLogPop(1111);
4651  return(true);
4652  }
4653  }
4654  }
4655  Utilities->CallLogPop(1112);
4656  return(false);
4657 }
4658 
4659 // ---------------------------------------------------------------------------
4660 
4661 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4662 {
4663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4664  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4665  Utilities->CallLogPop(480);
4666 }
4667 
4668 // ---------------------------------------------------------------------------
4669 
4671 {
4672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4673  if(TrackVector.size() == 0)
4674  {
4675  Utilities->CallLogPop(481);
4676  return;
4677  }
4678  for(unsigned int x = 0; x < TrackVector.size(); x++)
4679  {
4680  if(TrackElementAt(1114, x).TrackType == GapJump)
4681  {
4682  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4683  {
4684  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4685  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4686  {
4687  TrackElementAt(1118, x).Conn[0] = -1;
4688  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4689  continue; // to next 'x'
4690  }
4691 // here if gap connection is itself a GapJump
4692  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4693  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4694  // if not clear Conns & CLks
4695  {
4696  TrackElementAt(1121, x).Conn[0] = -1;
4697  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4698  continue; // to next 'x'
4699  }
4700 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4701 // hence no more action needed on these Conns & CLks
4702  }
4703  } // else //gap jump
4704 
4705  } // for x...
4706 // throw Exception("Test Exception");//test
4707  Utilities->CallLogPop(482);
4708 }
4709 
4710 // ---------------------------------------------------------------------------
4711 
4712 void TTrack::ResetSignals(int Caller)
4713 {
4714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4715  for(unsigned int x = 0; x < TrackVector.size(); x++)
4716  {
4717  if(TrackElementAt(1123, x).TrackType == SignalPost)
4718  {
4719  TrackElementAt(1124, x).Attribute = 0;
4720  TrackElementAt(1514, x).Failed = false;
4721  }
4722  }
4723  FailedSignalsVector.clear();
4724  Utilities->CallLogPop(483);
4725 }
4726 
4727 // ---------------------------------------------------------------------------
4728 
4729 void TTrack::ResetPoints(int Caller)
4730 {
4731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4732  for(unsigned int x = 0; x < TrackVector.size(); x++)
4733  {
4734  if(TrackElementAt(1125, x).TrackType == Points)
4735  {
4736  TrackElementAt(1126, x).Attribute = 0;
4737  TrackElementAt(1515, x).Failed = false;
4738  }
4739  }
4740  FailedPointsVector.clear();
4741  Utilities->CallLogPop(484);
4742 }
4743 
4744 // ---------------------------------------------------------------------------
4745 
4746 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4747 {
4748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4749  for(unsigned int x = 0; x < TrackVector.size(); x++)
4750  {
4751  if(TrackElementAt(1554, x).TrackType == Simple)
4752  {
4753  TrackElementAt(1555, x).Failed = false;
4754  }
4755  }
4756  TSRVector.clear();
4757  Utilities->CallLogPop(2550);
4758 }
4759 
4760 // ---------------------------------------------------------------------------
4761 
4762 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4763 {
4764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4765  if(TrackVector.empty())
4766  {
4767  TrackMap.clear();
4768  Utilities->CallLogPop(485);
4769  return(true);
4770  }
4771 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4772  THVPair TrackMapKeyPair;
4773 
4774  NewVector.clear();
4775  TTrackMapIterator TrackMapPtr;
4776 
4777  if(!TrackMap.empty())
4778  {
4779  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4780  {
4781  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4782  }
4783  }
4784  if(NewVector.size() != TrackMap.size())
4785  {
4786  throw Exception("Error - Map & Vector different sizes");
4787  }
4788  unsigned int NonZeroCount = 0;
4789 
4790  for(unsigned int x = 0; x < TrackVector.size(); x++)
4791  {
4792  if(TrackElementAt(1127, x).TrackType != Erase)
4793  {
4794  NonZeroCount++;
4795  }
4796  }
4797  if(NewVector.size() != NonZeroCount)
4798  {
4799  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4800  }
4802  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4803  TTrackMapEntry TrackMapEntry;
4804 
4805  for(unsigned int x = 0; x < TrackVector.size(); x++)
4806  {
4807  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4808  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4809  TrackMapEntry.first = TrackMapKeyPair;
4810  TrackMapEntry.second = x;
4811  if(!(TrackMap.insert(TrackMapEntry).second))
4812  {
4813  throw Exception("Error - map insertion failure, TrackVector in error");
4814  }
4815  }
4816 // All track now relocated in TrackVector, reset all Conns & CLks
4817  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4818  {
4819  for(unsigned int y = 0; y < 4; y++)
4820  {
4821  TrackElementAt(1130, x).Conn[y] = -1;
4822  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4823  }
4824  }
4825  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4826  CheckMapAndTrack(4); // test
4827  CheckMapAndInactiveTrack(4); // test
4828  CheckLocationNameMultiMap(8); // test
4829  if(!ResetGapsFromGapMap(1))
4830  {
4831  Utilities->CallLogPop(489);
4832  return(false);
4833  }
4834  Utilities->CallLogPop(490);
4835  return(true);
4836 }
4837 
4838 // ---------------------------------------------------------------------------
4839 
4840 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4841 {
4842  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4843  GapMap.clear();
4844  THVPair GapMapKeyPair, GapMapValuePair;
4845  TGapMapEntry GapMapEntry;
4846 
4847  for(unsigned int x = 0; x < TrackVector.size(); x++)
4848  {
4849  if(TrackElementAt(1132, x).TrackType == GapJump)
4850  {
4851  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4852  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4853  GapMapEntry.first = GapMapKeyPair;
4854  if(TrackElementAt(1135, x).Conn[0] == -1)
4855  {
4856  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4857  }
4858  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4859  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4860  GapMapEntry.second = GapMapValuePair;
4861  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4862  {
4863  GapMap.insert(GapMapEntry);
4864  }
4865  }
4866  }
4867  Utilities->CallLogPop(492);
4868 }
4869 
4870 // ---------------------------------------------------------------------------
4871 
4872 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4873 {
4874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4875 
4876 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4877  LocError = false;
4878  bool TrackElementPositionsOK = true;
4879 
4880  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4881  {
4882  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4883  {
4884  continue; // skip blank elements
4885  }
4886 // check footcrossing linkages
4887  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4888  {
4889  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4890  {
4891  ShowMessage(
4892  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4893  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4894  "can't connect to an underpass or vice versa)");
4895  HLoc = TrackElementAt(1141, x).HLoc;
4896  VLoc = TrackElementAt(1142, x).VLoc;
4897  LocError = true;
4898  Utilities->CallLogPop(493);
4899  return(false);
4900  }
4901  }
4902  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4903  {
4904  if(TrackElementAt(1143, x).Link[y] <= 0)
4905  {
4906  continue; // no link
4907  }
4908  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4909  {
4910  continue; // buffer
4911  }
4912  if(TrackElementAt(1146, x).Config[y] == Gap)
4913  {
4914  continue; // gaps set later from GapMap
4915  }
4916  // get required H & V for track element joining link 'y'
4917  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4918  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4919  // find track element if present
4920  bool ConnectionFoundFlag;
4921  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4922  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4923  {
4924  ShowMessage("Can't have a track element adjacent to a continuation exit");
4925  HLoc = TrackElementAt(1152, x).HLoc;
4926  VLoc = TrackElementAt(1153, x).VLoc;
4927  LocError = true;
4928  if(FinalCall)
4929  {
4930  throw Exception("Error in final track linkage - continuation adjacent to another element");
4931  }
4932  Utilities->CallLogPop(1539);
4933  return(false);
4934  }
4935  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4936  {
4937  continue;
4938  }
4939  if(ConnectionFoundFlag)
4940  {
4941  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4942  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4943  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4944  {
4945  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4946  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4947  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4948  TrackElementPositionsOK = false;
4949  }
4950  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4951  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4952  {
4953  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4954  // need room for a train (2 elements) without fouling points or signals
4955  TrackElementPositionsOK = false;
4956  }
4957  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4958  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4959  {
4960  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4961  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4962  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4963  // be named but needs the adjacent element named too
4964  TrackElementPositionsOK = false;
4965  }
4966  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4967  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4968  {
4969  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4970  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4971  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4972  TrackElementPositionsOK = false;
4973  }
4974  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4975  {
4976  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4977  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4978  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4979  TrackElementPositionsOK = false;
4980  }
4981  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4982  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4983  {
4984  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4985  TrackElementPositionsOK = false;
4986  }
4987  // if failed then set the invert values for the offending element
4988  if(!TrackElementPositionsOK)
4989  {
4990  HLoc = TrackElementAt(1183, x).HLoc;
4991  VLoc = TrackElementAt(1184, x).VLoc;
4992  LocError = true;
4993  if(FinalCall)
4994  {
4995  throw Exception("Error in track element positions in FinalCall");
4996  }
4997  Utilities->CallLogPop(494);
4998  return(false);
4999  }
5000  }
5001  // no 'else' here, if there's no link then will be picked up in 2nd pass
5002  }
5003  } // for(unsigned int x=0;x<TrackVector.size();x++)
5004 
5005 
5006 //2nd pass - looking for missing connections
5007  LocError = false;
5008  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5009  {
5010  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5011  {
5012  continue; // skip blank elements
5013  }
5014  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5015  {
5016  if(TrackElementAt(1440, x).Link[y] <= 0)
5017  {
5018  continue; // no link
5019  }
5020  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5021  {
5022  continue; // buffer
5023  }
5024  if(TrackElementAt(1443, x).Config[y] == Gap)
5025  {
5026  continue; // gaps set later from GapMap
5027  }
5028  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5029  {
5030  continue; //continuation
5031  }
5032  // get required H & V for track element joining link 'y'
5033  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5034  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5035  // find track element if present
5036  bool ConnectionFoundFlag;
5037  bool LinkMatchFound = false;
5038  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
5039  // if there isn't a connection set the invert values for the offending element
5040  if(ConnectionFoundFlag) //set the ConnLinkPos values
5041  {
5042  for(unsigned int a = 0; a < 4; a++)
5043  {
5044  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5045  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5046  {
5047  TrackElementAt(1182, x).ConnLinkPos[y] = a;
5048  // note - this ensures that if the connecting element is a leading point
5049  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5050  // (Points have the same link value for both [0] and [2])
5051  LinkMatchFound = true;
5052  break; // stop after first find or will find later link for leading point
5053  }
5054  }
5055  if(!LinkMatchFound)
5056  {
5057  HLoc = TrackElementAt(1446, x).HLoc;
5058  VLoc = TrackElementAt(1447, x).VLoc;
5059  LocError = true;
5060  if(FinalCall)
5061  {
5062  throw Exception("Error in final track linkage - - no matching link found");
5063  }
5064  Utilities->CallLogPop(495);
5065  return(false);
5066  }
5067  }
5068  else //error
5069  {
5070  HLoc = TrackElementAt(1185, x).HLoc;
5071  VLoc = TrackElementAt(1186, x).VLoc;
5072  LocError = true;
5073  if(FinalCall)
5074  {
5075  throw Exception("Error in final track linkage - connection not found");
5076  }
5077  Utilities->CallLogPop(2443);
5078  return(false);
5079  }
5080  }
5081  }
5082 //end of 2nd pass
5083 
5084  if(FinalCall)
5085  {
5087  }
5088 
5089 // confirmatiory checks that all ok - or throw error
5090  bool ConnErrorFlag = false;
5091 
5092  for(unsigned int x = 0; x < TrackVector.size(); x++)
5093  {
5094  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5095  {
5096  ConnErrorFlag = true;
5097  }
5098  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5099  {
5100  ConnErrorFlag = true;
5101  }
5102  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5103  {
5104  ConnErrorFlag = true;
5105  }
5106  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5107  {
5108  ConnErrorFlag = true;
5109  }
5110  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5111  {
5112  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5113  {
5114  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5115  {
5116  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5117  }
5118  }
5119  }
5120  }
5121  if(ConnErrorFlag)
5122  {
5123  if(FinalCall)
5124  {
5125  throw Exception("ConnError in LinkTrack - Final");
5126  }
5127  else
5128  {
5129  throw Exception("ConnError in LinkTrack - Precheck");
5130  }
5131  }
5132  bool CLkErrorFlag = false;
5133 
5134  for(unsigned int x = 0; x < TrackVector.size(); x++)
5135  {
5136  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5137  {
5138  CLkErrorFlag = true;
5139  }
5140  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5141  {
5142  CLkErrorFlag = true;
5143  }
5144  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5145  {
5146  CLkErrorFlag = true;
5147  }
5148  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5149  {
5150  CLkErrorFlag = true;
5151  }
5152  }
5153 
5154  if(CLkErrorFlag)
5155  {
5156  if(FinalCall)
5157  {
5158  throw Exception("CLkError in LinkTrack - Final");
5159  }
5160  else
5161  {
5162  throw Exception("CLkError in LinkTrack - Precheck");
5163  }
5164  }
5165 
5166 // set element lengths to min of 10m
5167  for(unsigned int x = 0; x < TrackVector.size(); x++)
5168  {
5169  if(TrackElementAt(1214, x).TrackType == Erase)
5170  {
5171  continue; // skip blank elements
5172  }
5173  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5174  {
5175  TrackElementAt(1216, x).Length01 = 10;
5176  }
5177  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5178  {
5179  TrackElementAt(1219, x).Length23 = 10;
5180  }
5181  }
5182 
5183  if(FinalCall) // ONLY at FinalCall, no point calling twice
5184  {
5185  CalcHLocMinEtc(3);
5186  }
5187 
5188  Utilities->CallLogPop(497);
5189  return(true);
5190 }
5191 
5192 // ---------------------------------------------------------------------------
5193 
5194 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5195 {
5196  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5197  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5198  {
5199  if(TrackElementAt(1220, x).TrackType == Erase)
5200  {
5201  continue; // skip blank elements
5202 
5203  }
5204 // check footcrossing linkages
5205  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5206  {
5207  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5208  {
5209  Utilities->CallLogPop(1127);
5210  return(false);
5211  }
5212  }
5213  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5214  {
5215  if(TrackElementAt(1223, x).Link[y] <= 0)
5216  {
5217  continue; // no link
5218  }
5219  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5220  {
5221  continue; // buffer
5222  }
5223  if(TrackElementAt(1226, x).Config[y] == Gap)
5224  {
5225  continue; // gaps set later from GapMap
5226 
5227  }
5228  // get required H & V for track element joining link 'y'
5229  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5230  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5231  // find track element if present
5232  bool ConnectionFoundFlag;
5233  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5234  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5235  {
5236  if(FinalCall)
5237  {
5238  throw Exception("Error in final track linkage - continuation adjacent to another element");
5239  }
5240  Utilities->CallLogPop(1540);
5241  return(false);
5242  }
5243  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5244  {
5245  continue;
5246  }
5247  if(ConnectionFoundFlag)
5248  {
5249  TrackElementAt(1234, x).Conn[y] = VecPos;
5250  bool LinkFoundFlag = false;
5251  // find connecting link in the newly found track element if there is one & make checks
5252  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5253  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5254  {
5255  Utilities->CallLogPop(1541);
5256  return(false);
5257  }
5258  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5259  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5260  {
5261  Utilities->CallLogPop(1542);
5262  return(false);
5263  }
5264  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5265  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5266  {
5267  Utilities->CallLogPop(1543);
5268  return(false);
5269  }
5270  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5271  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5272  {
5273  Utilities->CallLogPop(1981);
5274  return(false);
5275  }
5276 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5277  else if(TrackElementAt(, x).TrackType == Continuation)
5278  {
5279  int H = TrackElementAt(, x).HLoc;
5280  int V = TrackElementAt(, x).VLoc;
5281  bool FoundFlag = false;
5282  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5283  if(FoundFlag)
5284  {
5285  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5286  {
5287  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5288  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5289  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5290  if(FoundFlag)
5291  {
5292  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5293  {
5294  Utilities->CallLogPop();
5295  return false;
5296  }
5297  }
5298  else
5299  {
5300  Utilities->CallLogPop();
5301  return false;
5302  }
5303  }
5304  }
5305  }
5306 */
5307  for(unsigned int a = 0; a < 4; a++)
5308  {
5309  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5310  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5311  {
5312  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5313  // note - this ensures that if the connecting element is a leading point
5314  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5315  // (Points have the same link value for both [0] and [2])
5316  LinkFoundFlag = true;
5317  break; // stop after first find or will find later link for leading point
5318  }
5319  }
5320  if(!LinkFoundFlag)
5321  {
5322  if(FinalCall)
5323  {
5324  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5325  }
5326  Utilities->CallLogPop(1128);
5327  return(false);
5328  }
5329  }
5330  else // if(ConnectionFoundFlag)
5331  {
5332  if(FinalCall)
5333  {
5334  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5335  }
5336  Utilities->CallLogPop(1129);
5337  return(false);
5338  }
5339  }
5340  } // for(unsigned int x=0;x<TrackVector.size();x++)
5341 
5342  if(FinalCall)
5343  {
5345  }
5346 // final check
5347  bool ConnErrorFlag = false;
5348 
5349  for(unsigned int x = 0; x < TrackVector.size(); x++)
5350  {
5351  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5352  {
5353  ConnErrorFlag = true;
5354  }
5355  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5356  {
5357  ConnErrorFlag = true;
5358  }
5359  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5360  {
5361  ConnErrorFlag = true;
5362  }
5363  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5364  {
5365  ConnErrorFlag = true;
5366  }
5367  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5368  {
5369  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5370  {
5371  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5372  {
5373  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5374  }
5375  }
5376  }
5377  }
5378  if(ConnErrorFlag)
5379  {
5380  if(FinalCall)
5381  {
5382  throw Exception("ConnError in LinkTrack - Final");
5383  }
5384  else
5385  {
5386  throw Exception("ConnError in LinkTrack - Precheck");
5387  }
5388  }
5389  bool CLkErrorFlag = false;
5390 
5391  for(unsigned int x = 0; x < TrackVector.size(); x++)
5392  {
5393  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5394  {
5395  CLkErrorFlag = true;
5396  }
5397  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5398  {
5399  CLkErrorFlag = true;
5400  }
5401  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5402  {
5403  CLkErrorFlag = true;
5404  }
5405  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5406  {
5407  CLkErrorFlag = true;
5408  }
5409  }
5410 
5411  if(CLkErrorFlag)
5412  {
5413  if(FinalCall)
5414  {
5415  throw Exception("CLkError in LinkTrack - Final");
5416  }
5417  else
5418  {
5419  throw Exception("CLkError in LinkTrack - Precheck");
5420  }
5421  }
5422 // set element lengths to min of 10m
5423  for(unsigned int x = 0; x < TrackVector.size(); x++)
5424  {
5425  if(TrackElementAt(1284, x).TrackType == Erase)
5426  {
5427  continue; // skip blank elements
5428  }
5429  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5430  {
5431  TrackElementAt(1286, x).Length01 = 10;
5432  }
5433  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5434  {
5435  TrackElementAt(1289, x).Length23 = 10;
5436  }
5437  }
5438 
5439  if(FinalCall) // ONLY at FinalCall, no point calling twice
5440  {
5441  CalcHLocMinEtc(7);
5442  }
5443  Utilities->CallLogPop(1130);
5444  return(true);
5445 }
5446 
5447 // ---------------------------------------------------------------------------
5448 
5449 bool TTrack::IsTrackLinked(int Caller) // not used any more
5450 {
5451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5452  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5453  {
5454  if(TrackElementAt(1290, x).TrackType == Erase)
5455  {
5456  Utilities->CallLogPop(498);
5457  return(false);
5458  }
5459 // check foot linkages
5460  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5461  {
5462  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5463  {
5464  Utilities->CallLogPop(499);
5465  return(false);
5466  }
5467  }
5468  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5469  {
5470  if(TrackElementAt(1293, x).Link[y] <= 0)
5471  {
5472  continue; // no link
5473  }
5474  if(TrackElementAt(1294, x).Config[y] == End)
5475  {
5476  continue; // buffer or continuation
5477  }
5478  if(TrackElementAt(1295, x).Config[y] == Gap)
5479  {
5480  continue; // gaps set later from GapMap
5481 
5482  }
5483  // get required H & V for track element joining link 'y'
5484  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5485  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5486  // find track element if present
5487  bool ConnectionFoundFlag = false;
5488  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5489  if(ConnectionFoundFlag)
5490  {
5491  TrackElementAt(1300, x).Conn[y] = VecPos;
5492  // find connecting link in the newly found track element if there is one & make buffer check
5493  bool LinkFoundFlag = false;
5494  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5495  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5496  {
5497  Utilities->CallLogPop(500);
5498  return(false);
5499  }
5500  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5501  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5502  {
5503  Utilities->CallLogPop(501);
5504  return(false);
5505  }
5506  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5507  {
5508  Utilities->CallLogPop(502);
5509  return(false);
5510  }
5511  else
5512  {
5513  for(unsigned int a = 0; a < 4; a++)
5514  {
5515  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5516  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5517  {
5518  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5519  // note - this ensures that if the connecting element is a leading point
5520  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5521  // (Points have the same link value for both [0] and [2])
5522  LinkFoundFlag = true;
5523  break; // stop after first find or will find later link for leading point
5524  }
5525  }
5526  }
5527  if(!LinkFoundFlag)
5528  {
5529  Utilities->CallLogPop(503);
5530  return(false);
5531  }
5532  }
5533  else // if(ConnectionFoundFlag)
5534  {
5535  Utilities->CallLogPop(504);
5536  return(false);
5537  }
5538  }
5539  } // for(unsigned int x=0;x<TrackVector.size();x++)
5540 
5541 // final check
5542  bool ConnErrorFlag = false;
5543 
5544  for(unsigned int x = 0; x < TrackVector.size(); x++)
5545  {
5546  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5547  {
5548  ConnErrorFlag = true;
5549  }
5550  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5551  {
5552  ConnErrorFlag = true;
5553  }
5554  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5555  {
5556  ConnErrorFlag = true;
5557  }
5558  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5559  {
5560  ConnErrorFlag = true;
5561  }
5562  }
5563  if(ConnErrorFlag)
5564  {
5565  Utilities->CallLogPop(505);
5566  return(false);
5567  }
5568  bool CLkErrorFlag = false;
5569 
5570  for(unsigned int x = 0; x < TrackVector.size(); x++)
5571  {
5572  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5573  {
5574  CLkErrorFlag = true;
5575  }
5576  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5577  {
5578  CLkErrorFlag = true;
5579  }
5580  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5581  {
5582  CLkErrorFlag = true;
5583  }
5584  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5585  {
5586  CLkErrorFlag = true;
5587  }
5588  }
5589 
5590  if(CLkErrorFlag)
5591  {
5592  Utilities->CallLogPop(506);
5593  return(false);
5594  }
5595  Utilities->CallLogPop(507);
5596  return(true);
5597 }
5598 
5599 // ---------------------------------------------------------------------------
5600 
5602 {
5603  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5604  int Position1, Position2;
5605  TTrackElement TrackElement1, TrackElement2;
5606  TGapMapIterator GapMapPtr;
5607 
5608  if(!GapMap.empty())
5609  {
5610  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5611  {
5612  int HLoc1 = GapMapPtr->first.first;
5613  int VLoc1 = GapMapPtr->first.second;
5614  int HLoc2 = GapMapPtr->second.first;
5615  int VLoc2 = GapMapPtr->second.second;
5616  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5617  {
5618  throw Exception("Failed to find H & V for gap1, GapMap in error");
5619  }
5620  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5621  {
5622  throw Exception("Failed to find H & V for gap2, GapMap in error");
5623  }
5624  if(TrackElementAt(9, Position1).TrackType != GapJump)
5625  {
5626  throw Exception("Element at Pos1 not a gap, GapMap in error");
5627  }
5628  if(TrackElementAt(10, Position2).TrackType != GapJump)
5629  {
5630  throw Exception("Element at Pos2 not a gap, GapMap in error");
5631  }
5632  TrackElementAt(11, Position1).Conn[0] = Position2;
5633  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5634  TrackElementAt(13, Position2).Conn[0] = Position1;
5635  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5636  }
5637  }
5638  Utilities->CallLogPop(510);
5639  return(true);
5640 }
5641 
5642 // ---------------------------------------------------------------------------
5643 
5644 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5645 {
5646 // TIMPair MapEntry;
5647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5648  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5649  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5650  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5651  TLocationNameMultiMapEntry LocationNameEntry;
5652 
5653  LocationNameEntry.first = TrackElement.LocationName;
5654  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5655  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5656  {
5657 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5658 // could arise when loading old railways with multiple NonStationNamedLocs
5659  bool FoundFlag = false;
5660  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5661  if(FoundFlag)
5662  {
5663  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5664  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5665  {
5666  Utilities->CallLogPop(1813);
5667  return;
5668  }
5669  }
5670  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5671  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5672  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5673  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5674  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5675  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5676  if(TrackElement.FixedNamedLocationElement)
5677  {
5678  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5679  LocationNameMultiMap.insert(LocationNameEntry);
5680  }
5681  if(TrackElement.HLoc < HLocMin)
5682  {
5683  HLocMin = TrackElement.HLoc;
5684  }
5685  if(TrackElement.HLoc > HLocMax)
5686  {
5687  HLocMax = TrackElement.HLoc;
5688  }
5689  if(TrackElement.VLoc < VLocMin)
5690  {
5691  VLocMin = TrackElement.VLoc;
5692  }
5693  if(TrackElement.VLoc > VLocMax)
5694  {
5695  VLocMax = TrackElement.VLoc;
5696  }
5697  }
5698  else
5699  {
5700 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5701 // shouldn't arise but leave in as a safeguard
5702  bool FoundFlag = false;
5703  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5704  if(FoundFlag)
5705  {
5706  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5707  {
5708  Utilities->CallLogPop(1814);
5709  return;
5710  }
5711  }
5712  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5713  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5714  {
5715  TrackMapKeyPair.first = TrackElement.HLoc;
5716  TrackMapKeyPair.second = TrackElement.VLoc;
5717  TrackMapEntry.first = TrackMapKeyPair;
5718  TrackMapEntry.second = TrackVector.size() - 1;
5719  TrackMap.insert(TrackMapEntry);
5720  if(TrackElement.FixedNamedLocationElement)
5721  {
5722  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5723  LocationNameMultiMap.insert(LocationNameEntry);
5724  }
5725  if(TrackElement.HLoc < HLocMin)
5726  {
5727  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5728  }
5729  if(TrackElement.HLoc > HLocMax)
5730  {
5731  HLocMax = TrackElement.HLoc;
5732  }
5733  if(TrackElement.VLoc < VLocMin)
5734  {
5735  VLocMin = TrackElement.VLoc;
5736  }
5737  if(TrackElement.VLoc > VLocMax)
5738  {
5739  VLocMax = TrackElement.VLoc;
5740  }
5741  }
5742  }
5743 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5744 // CheckMapAndInactiveTrack(6);//test
5745 
5746 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5747 // with the Platforms until layout fully loaded
5748  Utilities->CallLogPop(511);
5749 }
5750 
5751 // ---------------------------------------------------------------------------
5752 
5753 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5754 {
5755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5756  AnsiString(VLoc));
5757  THVPair TrackMapKeyPair;
5758 
5759  FoundFlag = false;
5760  TTrackMapIterator TrackMapPtr;
5761 
5762  TrackMapKeyPair.first = HLoc;
5763  TrackMapKeyPair.second = VLoc;
5764  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5765  if(TrackMapPtr == TrackMap.end())
5766  {
5767  Utilities->CallLogPop(512);
5768  return(-1); // nothing found
5769  }
5770  else
5771  {
5772  FoundFlag = true;
5773  Utilities->CallLogPop(513);
5774  return(TrackMapPtr->second);
5775  }
5776 }
5777 
5778 // ---------------------------------------------------------------------------
5779 
5780 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5781 {
5782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5783  AnsiString(VLoc));
5784  THVPair TrackMapKeyPair;
5785  TTrackMapIterator TrackMapPtr;
5786 
5787  TrackMapKeyPair.first = HLoc;
5788  TrackMapKeyPair.second = VLoc;
5789  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5790  if(TrackMapPtr == TrackMap.end())
5791  {
5792  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5793  throw Exception(Message);
5794  }
5795  else
5796  {
5797  Utilities->CallLogPop(1943);
5798  return(TrackElementAt(871, TrackMapPtr->second));
5799  }
5800 }
5801 
5802 // ---------------------------------------------------------------------------
5803 
5804 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5805 { //modded at v2.9.2 to make Map & Vector references
5806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5807  AnsiString(VLoc));
5808  THVPair MapKeyPair;
5809  TTrackMapIterator MapPtr;
5810 
5811  MapKeyPair.first = HLoc;
5812  MapKeyPair.second = VLoc;
5813  MapPtr = Map.find(MapKeyPair);
5814  if(MapPtr == Map.end())
5815  {
5816  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5817  throw Exception(Message);
5818  }
5819  else
5820  {
5821  Utilities->CallLogPop(2280);
5822  return(Vector.at(MapPtr->second));
5823  }
5824 }
5825 
5826 // ---------------------------------------------------------------------------
5827 
5829 {
5830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5831  AnsiString(VLoc));
5832  THVPair InactiveTrackMapKeyPair;
5833  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5834 
5835  InactiveTrackMapKeyPair.first = HLoc;
5836  InactiveTrackMapKeyPair.second = VLoc;
5837  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5838  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5839  {
5840  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5841  throw Exception(Message);
5842  }
5843  else
5844  {
5845  Utilities->CallLogPop(1949);
5846  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5847  }
5848 }
5849 
5850 // ---------------------------------------------------------------------------
5851 
5852 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5853 {
5854  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5855  bool Present = true;
5856  THVPair TrackMapKeyPair;
5857  TTrackMapIterator TrackMapPtr;
5858 
5859  TrackMapKeyPair.first = HLoc;
5860  TrackMapKeyPair.second = VLoc;
5861  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5862  if(TrackMapPtr == TrackMap.end())
5863  {
5864  Present = false;
5865  }
5866  Utilities->CallLogPop(2057);
5867  return(Present);
5868 }
5869 
5870 // ---------------------------------------------------------------------------
5871 
5872 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5873 {
5874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5875  AnsiString(VLoc));
5876  bool Present = true;
5877  THVPair InactiveTrackMapKeyPair;
5878  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5879 
5880  InactiveTrackMapKeyPair.first = HLoc;
5881  InactiveTrackMapKeyPair.second = VLoc;
5882  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5883  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5884  {
5885  Present = false;
5886  }
5887  Utilities->CallLogPop(2058);
5888  return(Present);
5889 }
5890 
5891 // ---------------------------------------------------------------------------
5892 
5893 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5894 // max number of elements is 2, for platforms
5895 // note that both elements of RetPair may be the same, if only one present in map
5896 {
5897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5898  AnsiString(VLoc));
5899  THVPair InactiveTrackMapKeyPair;
5900  TIMPair RetPair;
5901  TInactiveTrackRange InactiveTrackRange;
5902 
5903  FoundFlag = false;
5904  InactiveTrackMapKeyPair.first = HLoc;
5905  InactiveTrackMapKeyPair.second = VLoc;
5906  if(InactiveTrack2MultiMap.empty())
5907  {
5908  RetPair.first = 0;
5909  RetPair.second = 0;
5910  Utilities->CallLogPop(1815);
5911  return(RetPair); // map empty
5912  }
5913  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5914  if(InactiveTrackRange.first == InactiveTrackRange.second)
5915  {
5916  RetPair.first = 0;
5917  RetPair.second = 0;
5918  Utilities->CallLogPop(514);
5919  return(RetPair); // nothing found
5920  }
5921  else
5922  {
5923  RetPair.first = InactiveTrackRange.first->second;
5924  RetPair.second = (--InactiveTrackRange.second)->second;
5925  FoundFlag = true;
5926  Utilities->CallLogPop(515);
5927  return(RetPair);
5928  }
5929 }
5930 
5931 // ---------------------------------------------------------------------------
5932 
5933 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
5934 {
5935 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5937  AnsiString(DivergingPosition));
5938  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5939  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5940  int SpeedTag1 = T1.SpeedTag;
5941  int SpeedTag2 = T2.SpeedTag;
5942 
5943  if((T1.Attribute) != (T2.Attribute))
5944  {
5945  Utilities->CallLogPop(516);
5946  return(false);
5947  }
5948  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5949  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5950  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5951  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5952  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5953  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5954  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5955  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5956  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5957  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5958  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5959  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5960  {
5961  Utilities->CallLogPop(517);
5962  return(true);
5963  }
5964  else
5965  {
5966  Utilities->CallLogPop(518);
5967  return(false);
5968  }
5969 }
5970 
5971 // ---------------------------------------------------------------------------
5972 
5973 /*
5974  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5975  {
5976  if(lower.second < higher.second) return true;
5977  else if(lower.second > higher.second) return false;
5978  else if(lower.second == higher.second)
5979  {
5980  if(lower.first < higher.first) return true;
5981  }
5982  return false;
5983  }
5984 */
5985 // ---------------------------------------------------------------------------
5986 
5987 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5988 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5989 {
5990  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5991  if(TrackElement.TrackType != GapJump)
5992  {
5993  throw Exception("Error, Wrong track type in PlotGap");
5994  }
5995  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5996  {
5997  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5998  }
5999  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6000  {
6001  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6002  }
6003  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6004  {
6005  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6006  }
6007  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6008  {
6009  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6010  }
6011  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6012  {
6013  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6014  }
6015  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6016  {
6017  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6018  }
6019  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6020  {
6021  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6022  }
6023  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6024  {
6025  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6026  }
6027  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6028  {
6029  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6030  }
6031  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6032  {
6033  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6034  }
6035  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6036  {
6037  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6038  }
6039  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6040  {
6041  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6042  }
6043  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6044  {
6045  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6046  }
6047  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6048  {
6049  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6050  }
6051  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6052  {
6053  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6054  }
6055  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6056  {
6057  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6058  }
6059  Utilities->CallLogPop(1101);
6060 }
6061 
6062 // ---------------------------------------------------------------------------
6063 
6064 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6065 {
6066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6067  TrackElement.PlotVariableTrackElement(7, Disp);
6068  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6069  {
6070  THVPair PosPair;
6071  PosPair.first = TrackElement.HLoc;
6072  PosPair.second = TrackElement.VLoc;
6073  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6074  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6075  {
6076  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6077  }
6078  }
6079  Utilities->CallLogPop(2403);
6080 }
6081 
6082 // ---------------------------------------------------------------------------
6083 
6084 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6085 {
6086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6087  if(TrackElement.TrackType != Points)
6088  {
6089  throw Exception("Error, Wrong track type in PlotPoints");
6090  }
6091  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6092  TrackElement.PlotVariableTrackElement(4, Disp);
6093  if(BothFillets)
6094  {
6095  if(TrackElement.SpeedTag < 28)
6096  {
6097  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6098  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6099  }
6100  else if(TrackElement.SpeedTag < 132)
6101  {
6102  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6103  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6104  }
6105  else
6106  {
6107  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6108  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6109  }
6110  }
6111  else if(!TrackElement.Failed) //not failed
6112  {
6113  if(TrackElement.SpeedTag < 28)
6114  {
6115  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6116  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6117  }
6118  else if(TrackElement.SpeedTag < 132)
6119  {
6120  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6121  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6122  }
6123  else
6124  {
6125  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6126  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6127  }
6128  }
6129  else //failed in fixed position
6130  {
6131  if(TrackElement.SpeedTag < 28)
6132  {
6133  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6134  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6135  }
6136  else if(TrackElement.SpeedTag < 132)
6137  {
6138  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6139  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6140  }
6141  else
6142  {
6143  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6144  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6145  }
6146  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6147  }
6148 // replot platform if required
6149  TIMPair IMPair;
6150  bool FoundFlag;
6151 
6152  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6153  if(FoundFlag)
6154  {
6155  // only one platform possible at points so only need to plot IMPair.first
6156  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6157  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6158  }
6159  Utilities->CallLogPop(519);
6160 }
6161 
6162 // ---------------------------------------------------------------------------
6163 
6164 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6165 {
6166 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6168  if(TrackElement.TrackType != SignalPost)
6169  {
6170  throw Exception("Error, Wrong track type in PlotSignal");
6171  }
6172  if(!TrackElement.Failed) //added at v2.13.0
6173  {
6174  for(int x = 0; x < 40; x++)
6175  {
6176  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6177  {
6178  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6179  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6180  // in case existing signal is a double yellow
6181  // plot platforms if present
6182  // Graphics::TBitmap* SignalPlatformGraphic;
6183  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6184  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6185  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6186  // to not be plotted with the above function.
6187  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6188  // now plot signal (double yellow overwrites most of signal platform if present)
6189  // additions at version 0.6 for other aspects & ground sigs
6190  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6191  {
6192  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6193  }
6194  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6195  {
6196  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6197  }
6198  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6199  {
6200  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6201  }
6202  else // 4 aspect
6203  {
6204  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6205  }
6206  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6207  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6208  {
6209  if(TrackElement.SpeedTag == 68)
6210  {
6211  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6212  }
6213  if(TrackElement.SpeedTag == 69)
6214  {
6215  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6216  }
6217  if(TrackElement.SpeedTag == 70)
6218  {
6219  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6220  }
6221  if(TrackElement.SpeedTag == 71)
6222  {
6223  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6224  }
6225  if(TrackElement.SpeedTag == 72)
6226  {
6227  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6228  }
6229  if(TrackElement.SpeedTag == 73)
6230  {
6231  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6232  }
6233  if(TrackElement.SpeedTag == 74)
6234  {
6235  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6236  }
6237  if(TrackElement.SpeedTag == 75)
6238  {
6239  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6240  }
6241  }
6242  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6243  // ground signal calling on, need to use normal proceed aspect
6244  {
6245  for(int x = 0; x < 40; x++)
6246  {
6247  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6248  {
6249  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6250  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6251  // plot special signal platform if present
6252  Graphics::TBitmap* SignalPlatformGraphic;
6253  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6254  // now plot signal
6255  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6256  }
6257  }
6258  }
6259  break;
6260  }
6261  }
6262  }
6263  else //failed added at v2.13.0
6264  {
6265  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6266  {
6267  for(int x = 0; x < 8; x++)
6268  {
6269  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6270  {
6271  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6272  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6273  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6274  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6275  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6276  break;
6277  }
6278  }
6279  }
6280  else
6281  {
6282  for(int x = 0; x < 8; x++)
6283  {
6284  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6285  {
6286  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6287  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6288  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6289  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6290  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6291  break;
6292  }
6293  }
6294  }
6295  }
6296  Utilities->CallLogPop(520);
6297 }
6298 
6299 // ---------------------------------------------------------------------------
6300 
6301 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6302 {
6303  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6304  bool FoundFlag;
6305  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6306 
6307  if(!FoundFlag)
6308  {
6309  Utilities->CallLogPop(2112);
6310  return;
6311  }
6312  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6313  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6314 
6315  // don't want 'else if' for the below as may need to plot 2 platforms
6316  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6317  {
6318  if(IAElement1.LocationName == "") // '2' will be same
6319  {
6320  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6321  }
6322  else
6323  {
6324  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6325  }
6326  }
6327  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6328  {
6329  if(IAElement1.LocationName == "") // '2' will be same
6330  {
6331  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6332  }
6333  else
6334  {
6335  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6336  }
6337  }
6338  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6339  {
6340  if(IAElement1.LocationName == "") // '2' will be same
6341  {
6342  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6343  }
6344  else
6345  {
6346  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6347  }
6348  }
6349  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6350  {
6351  if(IAElement1.LocationName == "") // '2' will be same
6352  {
6353  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6354  }
6355  else
6356  {
6357  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6358  }
6359  }
6360  Utilities->CallLogPop(2113);
6361 }
6362 
6363 // ---------------------------------------------------------------------------
6364 
6365 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6366 {
6367 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6369  AnsiString(VLoc));
6370 // find topmost LC, opening them all (to trains) in turn
6371  int UpStep = 0;
6372 
6373  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6374  {
6375  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6376  UpStep--;
6377  }
6378 // now find bottommost LC, opening them all (to trains) in turn
6379  int DownStep = 1;
6380 
6381  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6382  {
6383  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6384  DownStep++;
6385  }
6386 // find leftmost LC, opening them all (to trains) in turn
6387  int LeftStep = 0;
6388 
6389  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6390  {
6391  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6392  LeftStep--;
6393  }
6394 // now find rightmost LC, opening them all (to trains) in turn
6395  int RightStep = 1;
6396 
6397  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6398  {
6399  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6400  RightStep++;
6401  }
6402  Utilities->CallLogPop(1915);
6403 }
6404 
6405 // ---------------------------------------------------------------------------
6406 
6407 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6408 {
6409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6410 // work upwards setting all to manual
6411  int UpStep = -1;
6412 
6413  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6414  {
6415  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6416  UpStep--;
6417  }
6418 // work downwards setting all to manual
6419  int DownStep = 1;
6420 
6421  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6422  {
6423  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6424  DownStep++;
6425  }
6426 // work leftwards setting all to manual
6427  int LeftStep = -1;
6428 
6429  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6430  {
6431  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6432  LeftStep--;
6433  }
6434 // work rightwards setting all to manual
6435  int RightStep = 1;
6436 
6437  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6438  {
6439  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6440  RightStep++;
6441  }
6442  Utilities->CallLogPop(2242);
6443 }
6444 
6445 // ---------------------------------------------------------------------------
6446 
6447 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6448 {
6449  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6451  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6452  {
6453  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6454  {
6455  BarriersDownVector.at(x).TypeOfRoute = 2;
6456  break;
6457  }
6458  }
6459  Utilities->CallLogPop(2243);
6460 }
6461 
6462 // ---------------------------------------------------------------------------
6463 
6464 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6465 {
6466  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6467 // work upwards
6468  int UpStep = 0; //start with this location
6469 
6470  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6471  {
6472  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6473  {
6474  Utilities->CallLogPop(2244);
6475  return(true);
6476  }
6477  UpStep--;
6478  }
6479 // work downwards
6480  int DownStep = 1;
6481 
6482  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6483  {
6484  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6485  {
6486  Utilities->CallLogPop(2245);
6487  return(true);
6488  }
6489  DownStep++;
6490  }
6491 // work leftwards
6492  int LeftStep = -1;
6493 
6494  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6495  {
6496  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6497  {
6498  Utilities->CallLogPop(2246);
6499  return(true);
6500  }
6501  LeftStep--;
6502  }
6503 // work rightwards
6504  int RightStep = 1;
6505 
6506  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6507  {
6508  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6509  {
6510  Utilities->CallLogPop(2247);
6511  return(true);
6512  }
6513  RightStep++;
6514  }
6515  Utilities->CallLogPop(2248);
6516  return(false);
6517 }
6518 
6519 // ---------------------------------------------------------------------------
6520 
6521 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6522 {
6523  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6524  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6525  {
6526  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6527  {
6528  BDVectorPos = x;
6529  Utilities->CallLogPop(2249);
6530  return(true);
6531  }
6532  }
6533  BDVectorPos = -1;
6534  Utilities->CallLogPop(2250);
6535  return(false);
6536 }
6537 
6538 // ---------------------------------------------------------------------------
6539 
6540 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6541 // open to trains
6542 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6543 {
6544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6545  AnsiString(VLoc));
6546  if(!IsLCAtHV(4, HLoc, VLoc))
6547  {
6548  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6549  }
6550  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6551  {
6552  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6553  }
6554 // check for adjacent LCs & if so open (to trains)
6555  if(BaseElementSpeedTag == 1) // hor track element
6556  {
6557  // find topmost LC, opening them all (to trains) in turn
6558  int UpStep = 0;
6559  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6560  {
6561  UpStep--;
6562  }
6563  UpStep++;
6564  // now find bottommost LC, opening them all (to trains) in turn
6565  int DownStep = 1;
6566  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6567  {
6568  DownStep++;
6569  }
6570  DownStep--;
6571  // now plot graphics, UpStep is smallest & DownStep largest
6572  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6573  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6574  Graphics::TBitmap *RouteGraphic;
6575  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6576  if(TypeOfRoute == 1)
6577  {
6578  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6579  }
6580  else if(TypeOfRoute == 0)
6581  {
6582  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6583  }
6584  else //manual - no route
6585  {
6586  RouteGraphic = BaseGraphic;
6587  }
6588 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6589 // LinkSigRouteGraphicsPtr[1] ver }
6590 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6591 // LinkNonSigRouteGraphicsPtr[1] ver }
6592 
6593  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6594  {
6595  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6596  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6597  if(!Manual)
6598  {
6599  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6600  }
6601  else
6602  {
6603  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6604  }
6605  }
6606  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6607  {
6608  if(UpStep == 0)
6609  {
6610  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6611  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6612  if(!Manual)
6613  {
6614  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6615  }
6616  else
6617  {
6618  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6619  }
6620  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6621  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6622  if(!Manual)
6623  {
6624  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6625  }
6626  else
6627  {
6628  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6629  }
6630  }
6631  else
6632  {
6633  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6634  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6635  if(!Manual)
6636  {
6637  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6638  }
6639  else
6640  {
6641  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6642  }
6643  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6644  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6645  if(!Manual)
6646  {
6647  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6648  }
6649  else
6650  {
6651  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6652  }
6653  }
6654  }
6655  else // at least one plain graphic
6656  {
6657  if(UpStep == 0)
6658  {
6659  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6660  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6661  if(!Manual)
6662  {
6663  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6664  }
6665  else
6666  {
6667  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6668  }
6669  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6670  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6671  if(!Manual)
6672  {
6673  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6674  }
6675  else
6676  {
6677  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6678  }
6679  }
6680  else if(DownStep == 0)
6681  {
6682  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6683  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6684  if(!Manual)
6685  {
6686  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6687  }
6688  else
6689  {
6690  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6691  }
6692  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6693  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6694  if(!Manual)
6695  {
6696  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6697  }
6698  else
6699  {
6700  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6701  }
6702  }
6703  else
6704  {
6705  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6706  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6707  if(!Manual)
6708  {
6709  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6710  }
6711  else
6712  {
6713  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6714  }
6715  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6716  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6717  if(!Manual)
6718  {
6719  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6720  }
6721  else
6722  {
6723  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6724  }
6725  }
6726  for(int x = (UpStep + 1); x < DownStep; x++)
6727  {
6728  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6729  if(x == 0)
6730  {
6731  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6732  }
6733  else
6734  {
6735  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6736  }
6737  if(!Manual)
6738  {
6739  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6740  }
6741  else
6742  {
6743  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6744  }
6745  }
6746  }
6747  Disp->Update();
6748  Utilities->CallLogPop(1958);
6749  return;
6750  }
6751 
6752  else // ver track element
6753  {
6754  // find leftmost LC, opening them all (to trains) in turn
6755  int LStep = 0;
6756  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6757  {
6758  LStep--;
6759  }
6760  LStep++;
6761  // now find rightmost LC, opening them all (to trains) in turn
6762  int RStep = 1;
6763  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6764  {
6765  RStep++;
6766  }
6767  RStep--;
6768  // now plot graphics, LStep is smallest & RStep largest
6769  Graphics::TBitmap *RouteGraphic;
6770  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6771  if(TypeOfRoute == 1)
6772  {
6773  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6774  }
6775  else if(TypeOfRoute == 0)
6776  {
6777  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6778  }
6779  else //manual
6780  {
6781  RouteGraphic = BaseGraphic;
6782  }
6783 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6784 // LinkSigRouteGraphicsPtr[1] ver }
6785 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6786 // LinkNonSigRouteGraphicsPtr[1] ver }
6787  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6788  {
6789  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6790  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6791  if(!Manual)
6792  {
6793  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6794  }
6795  else
6796  {
6797  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6798  }
6799  }
6800  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6801  {
6802  if(LStep == 0)
6803  {
6804  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6805  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6806  if(!Manual)
6807  {
6808  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6809  }
6810  else
6811  {
6812  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6813  }
6814  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6815  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6816  if(!Manual)
6817  {
6818  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6819  }
6820  else
6821  {
6822  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6823  }
6824  }
6825  else
6826  {
6827  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6828  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6829  if(!Manual)
6830  {
6831  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6832  }
6833  else
6834  {
6835  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6836  }
6837  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6838  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6839  if(!Manual)
6840  {
6841  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6842  }
6843  else
6844  {
6845  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6846  }
6847  }
6848  }
6849  else // at least one plain graphic
6850  {
6851  if(LStep == 0)
6852  {
6853  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6854  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6855  if(!Manual)
6856  {
6857  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6858  }
6859  else
6860  {
6861  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6862  }
6863  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6864  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6865  if(!Manual)
6866  {
6867  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6868  }
6869  else
6870  {
6871  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6872  }
6873  }
6874  else if(RStep == 0)
6875  {
6876  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6877  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6878  if(!Manual)
6879  {
6880  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6881  }
6882  else
6883  {
6884  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6885  }
6886  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6887  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6888  if(!Manual)
6889  {
6890  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6891  }
6892  else
6893  {
6894  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6895  }
6896  }
6897  else
6898  {
6899  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6900  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6901  if(!Manual)
6902  {
6903  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6904  }
6905  else
6906  {
6907  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6908  }
6909  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6910  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6911  if(!Manual)
6912  {
6913  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6914  }
6915  else
6916  {
6917  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6918  }
6919  }
6920  for(int x = (LStep + 1); x < RStep; x++)
6921  {
6922  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6923  if(x == 0)
6924  {
6925  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6926  }
6927  else
6928  {
6929  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6930  }
6931  if(!Manual)
6932  {
6933  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6934  }
6935  else
6936  {
6937  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6938  }
6939  }
6940  }
6941  Disp->Update();
6942  Utilities->CallLogPop(1896);
6943  return;
6944  }
6945 }
6946 
6947 // ---------------------------------------------------------------------------
6948 
6949 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6950 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6951 {
6952  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6953  AnsiString(HLoc) + "," + AnsiString(VLoc));
6954  if(!IsLCAtHV(29, HLoc, VLoc))
6955  {
6956  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6957  }
6958  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6959  {
6960  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6961  }
6962 // check for adjacent LCs & if so open (to trains)
6963  if(BaseElementSpeedTag == 1) // hor track element
6964  {
6965  // find topmost LC, opening them all (to trains) in turn
6966  int UpStep = 0;
6967  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6968  {
6969  UpStep--;
6970  }
6971  UpStep++;
6972  // now find bottommost LC, opening them all (to trains) in turn
6973  int DownStep = 1;
6974  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6975  {
6976  DownStep++;
6977  }
6978  DownStep--;
6979  // now plot graphics, UpStep is smallest & DownStep largest
6980  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6981  {
6982  if(!Manual)
6983  {
6984  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6985  }
6986  else
6987  {
6988  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6989  }
6990  }
6991  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6992  {
6993  if(!Manual)
6994  {
6995  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6996  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6997  }
6998  else
6999  {
7000  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7001  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7002  }
7003  }
7004  else // at least one plain graphic
7005  {
7006  if(!Manual)
7007  {
7008  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7009  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7010  for(int x = (UpStep + 1); x < DownStep; x++)
7011  {
7012  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7013  }
7014  }
7015  else
7016  {
7017  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7018  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7019  for(int x = (UpStep + 1); x < DownStep; x++)
7020  {
7021  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7022  }
7023  }
7024  }
7025  // set markers
7026  for(int x = UpStep; x <= DownStep; x++)
7027  {
7028  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7029  }
7030  Display->Update();
7031  Utilities->CallLogPop(1944);
7032  return;
7033  }
7034 
7035  else // ver track element
7036  {
7037  // find leftmost LC, opening them all (to trains) in turn
7038  int LStep = 0;
7039  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7040  {
7041  LStep--;
7042  }
7043  LStep++;
7044  // now find rightmost LC, opening them all (to trains) in turn
7045  int RStep = 1;
7046  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7047  {
7048  RStep++;
7049  }
7050  RStep--;
7051  // now plot graphics, LStep is smallest & RStep largest
7052  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7053  {
7054  if(!Manual)
7055  {
7056  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7057  }
7058  else
7059  {
7060  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7061  }
7062  }
7063  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7064  {
7065  if(!Manual)
7066  {
7067  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7068  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7069  }
7070  else
7071  {
7072  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7073  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7074  }
7075  }
7076  else // at least one plain graphic
7077  {
7078  if(!Manual)
7079  {
7080  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7081  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7082  for(int x = (LStep + 1); x < RStep; x++)
7083  {
7084  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7085  }
7086  }
7087  else
7088  {
7089  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7090  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7091  for(int x = (LStep + 1); x < RStep; x++)
7092  {
7093  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7094  }
7095  }
7096  }
7097  // set markers
7098  for(int x = LStep; x <= RStep; x++)
7099  {
7100  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7101  }
7102  Disp->Update();
7103  Utilities->CallLogPop(1945);
7104  return;
7105  }
7106 }
7107 
7108 // ---------------------------------------------------------------------------
7109 
7110 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7111 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7112 {
7113  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7114  AnsiString(VLoc));
7115  if(!IsLCAtHV(9, HLoc, VLoc))
7116  {
7117  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7118  }
7119  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7120  {
7121  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7122  }
7123 // check for adjacent LCs & if so close (to trains)
7124  if(BaseElementSpeedTag == 1) // hor track element
7125  {
7126  // find topmost LC, closing them all (to trains) in turn
7127  int UpStep = 0;
7128  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7129  {
7130  UpStep--;
7131  }
7132  UpStep++;
7133  // now find bottommost LC, opening them all (to trains) in turn
7134  int DownStep = 1;
7135  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7136  {
7137  DownStep++;
7138  }
7139  DownStep--;
7140  // now plot graphics, UpStep is smallest & DownStep largest
7141  for(int x = UpStep; x < (DownStep + 1); x++)
7142  {
7143  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7144  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7145  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7146  }
7147  Disp->Update();
7148  Utilities->CallLogPop(1959);
7149  return;
7150  }
7151 
7152  else // ver track element
7153  {
7154  // find leftmost LC, closing them all (to trains) in turn
7155  int LStep = 0;
7156  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7157  {
7158  LStep--;
7159  }
7160  LStep++;
7161  // now find rightmost LC, opening them all (to trains) in turn
7162  int RStep = 1;
7163  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7164  {
7165  RStep++;
7166  }
7167  RStep--;
7168  // now plot graphics, LStep is smallest & RStep largest
7169  for(int x = LStep; x < (RStep + 1); x++)
7170  {
7171  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7172  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7173  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7174  }
7175  Disp->Update();
7176  Utilities->CallLogPop(1960);
7177  return;
7178  }
7179 }
7180 
7181 // ---------------------------------------------------------------------------
7182 
7183 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7184 // closed to trains
7185 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7186 {
7187  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7188  AnsiString(HLoc) + "," + AnsiString(VLoc));
7189  if(!IsLCAtHV(34, HLoc, VLoc))
7190  {
7191  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7192  }
7193  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7194  {
7195  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7196  }
7197  TTrackElement TE;
7198 
7199 // check for adjacent LCs & if so close (to trains)
7200  if(BaseElementSpeedTag == 1) // hor track element
7201  {
7202  // find topmost LC, closing them all (to trains) in turn
7203  int UpStep = 0;
7204  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7205  {
7206  UpStep--;
7207  }
7208  UpStep++;
7209  // now find bottommost LC, opening them all (to trains) in turn
7210  int DownStep = 1;
7211  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7212  {
7213  DownStep++;
7214  }
7215  DownStep--;
7216  // now plot graphics, UpStep is smallest & DownStep largest
7217  for(int x = UpStep; x <= DownStep; x++)
7218  {
7219  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7220  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7221  }
7222  Display->Update();
7223  Utilities->CallLogPop(1946);
7224  return;
7225  }
7226 
7227  else // ver track element
7228  {
7229  // find leftmost LC, closing them all (to trains) in turn
7230  int LStep = 0;
7231  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7232  {
7233  LStep--;
7234  }
7235  LStep++;
7236  // now find rightmost LC, opening them all (to trains) in turn
7237  int RStep = 1;
7238  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7239  {
7240  RStep++;
7241  }
7242  RStep--;
7243  // now plot graphics, LStep is smallest & RStep largest
7244  for(int x = LStep; x <= RStep; x++)
7245  {
7246  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7247  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7248  }
7249  Display->Update();
7250  Utilities->CallLogPop(1947);
7251  return;
7252  }
7253 }
7254 
7255 // ---------------------------------------------------------------------------
7256 
7257 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7258 {
7259  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7260  Graphics::TBitmap *RouteGraphic;
7261  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7262 
7263  if(BaseElementSpeedTag == 1)
7264  {
7265  if(TypeOfRoute == 1)
7266  {
7267  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7268  }
7269  else if(TypeOfRoute == 0)
7270  {
7271  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7272  }
7273  else //manual
7274  {
7275  RouteGraphic = BaseGraphic;
7276  }
7277  if(State == Raising)
7278  {
7279  RouteGraphic = BaseGraphic;
7280  }
7281  }
7282  else
7283  {
7284  BaseGraphic = RailGraphics->gl2;
7285  if(TypeOfRoute == 1)
7286  {
7287  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7288  }
7289  else if(TypeOfRoute == 0)
7290  {
7291  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7292  }
7293  else
7294  {
7295  RouteGraphic = BaseGraphic; //manual
7296  }
7297  if(State == Raising)
7298  {
7299  RouteGraphic = BaseGraphic;
7300  }
7301  }
7302  int UpStep = 0;
7303 
7304  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7305  {
7306  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7307  if(UpStep == 0)
7308  {
7309  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7310  }
7311  else
7312  {
7313  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7314  }
7315  UpStep--;
7316  }
7317 // now find bottommost LC, opening them all (to trains) in turn
7318  int DownStep = 1;
7319 
7320  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7321  {
7322  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7323  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7324  DownStep++;
7325  }
7326  int LeftStep = 0;
7327 
7328  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7329  {
7330  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7331  if(LeftStep == 0)
7332  {
7333  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7334  }
7335  else
7336  {
7337  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7338  }
7339  LeftStep--;
7340  }
7341 // now find rightmost LC, opening them all (to trains) in turn
7342  int RightStep = 1;
7343 
7344  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7345  {
7346  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7347  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7348  RightStep++;
7349  }
7350  Disp->Update();
7351  Utilities->CallLogPop(1914);
7352 }
7353 
7354 // ---------------------------------------------------------------------------
7355 
7356 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7357 {
7358 // return false for no LC there, flashing or a closed (to trains) LC
7359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7360  bool FoundFlag;
7361  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7362 
7363  if(!FoundFlag)
7364  {
7365  Utilities->CallLogPop(1898);
7366  return(false);
7367  }
7368  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7369  {
7370  Utilities->CallLogPop(1899);
7371  return(false);
7372  }
7373  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7374  {
7375  Utilities->CallLogPop(1900);
7376  return(true);
7377  }
7378  Utilities->CallLogPop(1901);
7379  return(false);
7380 }
7381 
7382 // ---------------------------------------------------------------------------
7383 
7384 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7385 {
7386 // return false for no LC there, flashing LC or open (to trains) LC
7387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7388  bool FoundFlag;
7389  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7390 
7391  if(!FoundFlag)
7392  {
7393  Utilities->CallLogPop(1922);
7394  return(false);
7395  }
7396  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7397  {
7398  Utilities->CallLogPop(1923);
7399  return(false);
7400  }
7401  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7402  {
7403  Utilities->CallLogPop(1924);
7404  return(true);
7405  }
7406  Utilities->CallLogPop(1925);
7407  return(false);
7408 }
7409 
7410 // ---------------------------------------------------------------------------
7411 
7412 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7413 {
7414 // return true for barrier in process of moving
7415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7416  bool FoundFlag;
7417  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7418 
7419  if(!FoundFlag)
7420  {
7421  Utilities->CallLogPop(1918);
7422  return(false);
7423  }
7424  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7425  {
7426  Utilities->CallLogPop(1919);
7427  return(false);
7428  }
7429  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7430  {
7431  Utilities->CallLogPop(1920);
7432  return(true);
7433  }
7434  Utilities->CallLogPop(1921);
7435  return(false);
7436 }
7437 
7438 // ---------------------------------------------------------------------------
7439 
7440 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7441 {
7442 // return true for an LC at H&V
7443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7444  bool FoundFlag;
7445  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7446 
7447  if(!FoundFlag)
7448  {
7449  Utilities->CallLogPop(1902);
7450  return(false);
7451  }
7452  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7453  {
7454  Utilities->CallLogPop(1903);
7455  return(false);
7456  }
7457  Utilities->CallLogPop(1904);
7458  return(true);
7459 }
7460 
7461 // ---------------------------------------------------------------------------
7462 
7463 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7464 {
7465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7466  AnsiString(Attr));
7467  bool FoundFlag;
7468  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7469 
7470  if(!FoundFlag)
7471  {
7472  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7473  }
7474  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7475  {
7476  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7477  }
7478  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7479  Utilities->CallLogPop(1905);
7480  return;
7481 }
7482 
7483 // ---------------------------------------------------------------------------
7484 
7486 {
7487  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7488  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7489  {
7490  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7491  if(InactiveTrackElement.TrackType == LevelCrossing)
7492  {
7493  InactiveTrackElementAt(141, x).Attribute = 0;
7494  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7495  }
7496  }
7497  Utilities->CallLogPop(1913);
7498  return;
7499 }
7500 
7501 // ---------------------------------------------------------------------------
7502 
7503 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7504 {
7505 // return true if there is either a route set or being set on any element or a train on any element
7506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7507  "," + AnsiString(VLoc));
7508 
7509  THVPair TrackMapKeyPair;
7510  TTrack::TTrackMapIterator TrackMapPtr;
7511  int DummyRouteNumber;
7512 
7513  TrainPresent = false;
7514 // find topmost LC, checking each for routes & trains
7515  int UpStep = 0;
7516 
7517  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7518  {
7519  TrackMapKeyPair.first = HLoc;
7520  TrackMapKeyPair.second = VLoc + UpStep;
7521  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7522  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7523  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7524  {
7525  Utilities->CallLogPop(1932);
7526  return(true);
7527  }
7528  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7529  {
7530  TrainPresent = true;
7531  Utilities->CallLogPop(1933);
7532  return(true);
7533  }
7534  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7535  {
7536  Utilities->CallLogPop(2274);
7537  return(true);
7538  }
7539  UpStep--;
7540  }
7541 // now find bottommost LC, opening them all (to trains) in turn
7542  int DownStep = 1;
7543 
7544  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7545  {
7546  TrackMapKeyPair.first = HLoc;
7547  TrackMapKeyPair.second = VLoc + DownStep;
7548  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7549  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7550  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7551  {
7552  Utilities->CallLogPop(1934);
7553  return(true);
7554  }
7555  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7556  {
7557  TrainPresent = true;
7558  Utilities->CallLogPop(1935);
7559  return(true);
7560  }
7561  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7562  {
7563  Utilities->CallLogPop(2275);
7564  return(true);
7565  }
7566  DownStep++;
7567  }
7568 // find leftmost LC
7569  int LeftStep = 0;
7570 
7571  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7572  {
7573  TrackMapKeyPair.first = HLoc + LeftStep;
7574  TrackMapKeyPair.second = VLoc;
7575  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7576  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7577  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7578  {
7579  Utilities->CallLogPop(1936);
7580  return(true);
7581  }
7582  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7583  {
7584  TrainPresent = true;
7585  Utilities->CallLogPop(1937);
7586  return(true);
7587  }
7588  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7589  {
7590  Utilities->CallLogPop(2276);
7591  return(true);
7592  }
7593  LeftStep--;
7594  }
7595 // now find rightmost LC, opening them all (to trains) in turn
7596  int RightStep = 1;
7597 
7598  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7599  {
7600  TrackMapKeyPair.first = HLoc + RightStep;
7601  TrackMapKeyPair.second = VLoc;
7602  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7603  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7604  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7605  {
7606  Utilities->CallLogPop(1938);
7607  return(true);
7608  }
7609  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7610  {
7611  TrainPresent = true;
7612  Utilities->CallLogPop(1939);
7613  return(true);
7614  }
7615  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7616  {
7617  Utilities->CallLogPop(2277);
7618  return(true);
7619  }
7620  RightStep++;
7621  }
7622  Utilities->CallLogPop(1940);
7623  return(false);
7624 }
7625 
7626 // ---------------------------------------------------------------------------
7627 
7628 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7629 {
7630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7631  for(unsigned int x = 0; x < SearchVector.size(); x++)
7632  {
7633  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7634  {
7635  Utilities->CallLogPop(2278);
7636  return(true);
7637  }
7638  }
7639  Utilities->CallLogPop(2279);
7640  return(false);
7641 }
7642 
7643 // ---------------------------------------------------------------------------
7644 
7645 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7646 {
7647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7648  AnsiString(HLoc) + "," + AnsiString(VLoc));
7649  if(!IsLCAtHV(60, HLoc, VLoc))
7650  {
7651  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7652  }
7653 
7654 // check for adjacent LCs
7655  // find topmost LC
7656  int UpStep = 0;
7657  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7658  {
7659  UpStep--;
7660  }
7661  UpStep++;
7662  // now find bottommost LC, opening them all (to trains) in turn
7663  int DownStep = 1;
7664  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7665  {
7666  DownStep++;
7667  }
7668  DownStep--;
7669  // now plot graphics, UpStep is smallest & DownStep largest
7670  for(int x = UpStep; x <= DownStep; x++)
7671  {
7672  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7673  }
7674 
7675  // find leftmost LC, closing them all (to trains) in turn
7676  int LStep = 0;
7677  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7678  {
7679  LStep--;
7680  }
7681  LStep++;
7682  // now find rightmost LC, opening them all (to trains) in turn
7683  int RStep = 1;
7684  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7685  {
7686  RStep++;
7687  }
7688  RStep--;
7689  // now plot graphics, LStep is smallest & RStep largest
7690  for(int x = LStep; x <= RStep; x++)
7691  {
7692  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7693  }
7694  Display->Update();
7695  Utilities->CallLogPop(2315);
7696  return;
7697 }
7698 
7699 // ---------------------------------------------------------------------------
7700 
7701 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7702 {
7703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7704  if(TrackElement.TrackType != Points)
7705  {
7706  throw Exception("Error, Wrong track type in GetFilletGraphic");
7707  }
7708  if(TrackElement.SpeedTag < 28)
7709  {
7710  Utilities->CallLogPop(521);
7711  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7712  }
7713  else if(TrackElement.SpeedTag < 132)
7714  {
7715  Utilities->CallLogPop(522);
7716 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7717  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7718  }
7719  else
7720  {
7721  Utilities->CallLogPop(1537);
7722  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7723  }
7724 }
7725 
7726 // ---------------------------------------------------------------------------
7727 
7729 {
7730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7731  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7732  {
7733  TrackElementAt(1351, x).TrainIDOnElement = -1;
7736  }
7737  Utilities->CallLogPop(1342);
7738 }
7739 
7740 // ---------------------------------------------------------------------------
7741 
7742 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7743 /*
7744  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7745 */
7746 {
7747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7748  AnsiString(ScreenPosV));
7749  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7750  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7751 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7752  Utilities->CallLogPop(535);
7753 }
7754 
7755 // ---------------------------------------------------------------------------
7756 
7757 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7758 /*
7759  Converts the screen position to the true (without offsets) position
7760 */
7761 {
7762  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7763  AnsiString(ScreenPosV));
7764  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7765  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7766  Utilities->CallLogPop(536);
7767 }
7768 
7769 // ---------------------------------------------------------------------------
7770 
7771 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7772 {
7773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7774  AnsiString(VPosTrue));
7775  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7776  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7777  Utilities->CallLogPop(537);
7778 }
7779 
7780 // ---------------------------------------------------------------------------
7781 
7782 void TTrack::CheckMapAndTrack(int Caller) // test
7783 {
7784  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7785  int Zeroes = 0;
7786  bool FoundFlag;
7787 
7788  for(unsigned int a = 0; a < TrackVector.size(); a++)
7789  {
7790  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7791  if(CheckElement.SpeedTag == 0)
7792  {
7793  Zeroes++; // zeroed elements not saved in map
7794  }
7795  else
7796  {
7797  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7798  if(!FoundFlag)
7799  {
7800  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7801  " in TrackMap, Caller=" + (AnsiString)Caller);
7802  }
7803  if(MapVecPos != (int)a)
7804  {
7805  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7806  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7807  (AnsiString)Caller);
7808  }
7809  }
7810  }
7811  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7812  {
7813  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7814  " Caller=" + (AnsiString)Caller);
7815  }
7816  Utilities->CallLogPop(538);
7817  return;
7818 }
7819 
7820 // ---------------------------------------------------------------------------
7821 
7822 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7823 {
7824  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7825  bool FoundFlag;
7826  TIMPair InactivePair;
7827 
7828  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7829  {
7830  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7831  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7832  if(!FoundFlag)
7833  {
7834  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7835  " in InactiveMap, Caller=" + (AnsiString)Caller);
7836  }
7837  if((InactivePair.first != a) && (InactivePair.second != a))
7838  {
7839  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7840  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7841  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7842  }
7843  }
7844  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7845  {
7846  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7847  " Caller=" + (AnsiString)Caller);
7848  }
7849  Utilities->CallLogPop(539);
7850 }
7851 
7852 // ---------------------------------------------------------------------------
7853 
7854 void TTrack::CheckGapMap(int Caller) // test
7855 {
7856  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7857  int Position1, Position2;
7858  TTrackElement TrackElement1, TrackElement2;
7859  TGapMapIterator GapMapPtr;
7860 
7861  if(!GapMap.empty())
7862  {
7863  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7864  {
7865  int HLoc1 = GapMapPtr->first.first;
7866  int VLoc1 = GapMapPtr->first.second;
7867  int HLoc2 = GapMapPtr->second.first;
7868  int VLoc2 = GapMapPtr->second.second;
7869  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7870  {
7871  throw Exception("Failed to find H & V for gap1, GapMap in error");
7872  }
7873  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7874  {
7875  throw Exception("Failed to find H & V for gap2, GapMap in error");
7876  }
7877  if(TrackElementAt(17, Position1).TrackType != GapJump)
7878  {
7879  throw Exception("Element at Pos1 not a gap, GapMap in error");
7880  }
7881  if(TrackElementAt(18, Position2).TrackType != GapJump)
7882  {
7883  throw Exception("Element at Pos2 not a gap, GapMap in error");
7884  }
7885  }
7886  }
7887  unsigned int GapCount = 0;
7888 
7889  for(unsigned int a = 0; a < TrackVector.size(); a++)
7890  {
7891  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7892  if(CheckElement.TrackType == GapJump)
7893  {
7894  GapCount++;
7895  }
7896  }
7897  if((GapMap.size() * 2) != GapCount)
7898  {
7899  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7900  (AnsiString)Caller);
7901  }
7902  Utilities->CallLogPop(540);
7903 }
7904 
7905 // ---------------------------------------------------------------------------
7906 
7907 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7908 {
7909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7910  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7911  {
7912  if(TrackFinished)
7913  {
7914  throw Exception("Error - TrackFinished with erase element still present");
7915  }
7916  Utilities->CallLogPop(541);
7917  return; // erased element, can't set ID
7918  }
7919  AnsiString IDString;
7920 
7921  if(TrackElement.HLoc < 0)
7922  {
7923  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7924  }
7925  else
7926  {
7927  IDString = AnsiString(TrackElement.HLoc) + "-";
7928  }
7929  if(TrackElement.VLoc < 0)
7930  {
7931  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7932  }
7933  else
7934  {
7935  IDString += AnsiString(TrackElement.VLoc);
7936  }
7937  TrackElement.ElementID = IDString;
7938  Utilities->CallLogPop(542);
7939 }
7940 
7941 // ---------------------------------------------------------------------------
7942 
7943 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7944 {
7945 // e.g. "8-13", "00008-13", "N43-N127", etc
7946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
7947  int DelimPos;
7948 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
7949  {
7950  for(int x = 1; x < String.Length() + 1; x++)
7951  {
7952  if(String.IsDelimiter("-", x))
7953  {
7954  DelimPos = x;
7955  break;
7956  }
7957  if(x == String.Length())
7958  {
7959  if(GiveMessages)
7960  {
7961  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7962  }
7963  Utilities->CallLogPop(543);
7964  return(-1);
7965  }
7966  }
7967  if(DelimPos == 1)
7968  {
7969  if(GiveMessages)
7970  {
7971  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7972  }
7973  Utilities->CallLogPop(544);
7974  return(-1);
7975  }
7976  if(DelimPos == String.Length())
7977  {
7978  if(GiveMessages)
7979  {
7980  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7981  }
7982  Utilities->CallLogPop(545);
7983  return(-1);
7984  }
7985  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7986  {
7987  if(GiveMessages)
7988  {
7989  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7990  }
7991  Utilities->CallLogPop(1508);
7992  return(-1);
7993  }
7994  int HLoc, VLoc;
7995 
7996  if(String.SubString(1, 1) != "N")
7997  {
7998  for(int x = 1; x < DelimPos; x++)
7999  {
8000  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8001  {
8002  if(GiveMessages)
8003  {
8004  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8005  }
8006  Utilities->CallLogPop(546);
8007  return(-1);
8008  }
8009  }
8010  }
8011  if(String.SubString(1, 1) == "N")
8012  {
8013  for(int x = 2; x < DelimPos; x++)
8014  {
8015  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8016  {
8017  if(GiveMessages)
8018  {
8019  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8020  }
8021  Utilities->CallLogPop(763);
8022  return(-1);
8023  }
8024  }
8025  }
8026  if(String.SubString(1, 1) == "N")
8027  {
8028  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8029  }
8030  else
8031  {
8032  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8033  }
8034  if(String.SubString(DelimPos + 1, 1) != "N")
8035  {
8036  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8037  {
8038  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8039  {
8040  if(GiveMessages)
8041  {
8042  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8043  }
8044  Utilities->CallLogPop(547);
8045  return(-1);
8046  }
8047  }
8048  }
8049  if(String.SubString(DelimPos + 1, 1) == "N")
8050  {
8051  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8052  {
8053  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8054  {
8055  if(GiveMessages)
8056  {
8057  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8058  }
8059  Utilities->CallLogPop(764);
8060  return(-1);
8061  }
8062  }
8063  }
8064  if(String.SubString(DelimPos + 1, 1) == "N")
8065  {
8066  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8067  }
8068  else
8069  {
8070  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8071  }
8072  THVPair HVPair(HLoc, VLoc);
8073  TTrackMapIterator TrackMapPtr;
8074 
8075  TrackMapPtr = TrackMap.find(HVPair);
8076  if(TrackMapPtr == TrackMap.end())
8077  {
8078  if(GiveMessages)
8079  {
8080  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8081  }
8082  Utilities->CallLogPop(548);
8083  return(-1);
8084  }
8085  Utilities->CallLogPop(549);
8086  return(TrackMapPtr->second);
8087  }
8088  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8089  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8090  {
8091  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8092  Utilities->CallLogPop(2481);
8093  return(-1);
8094  }
8095 }
8096 
8097 // ---------------------------------------------------------------------------
8098 
8099 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8100 /*
8101  True for linked properly at both ends
8102 */
8103 {
8104  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8105  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8106  int HLoc = TrackElement.HLoc;
8107  int VLoc = TrackElement.VLoc;
8108 
8109  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8110  {
8111  Utilities->CallLogPop(1821);
8112  return(false);
8113  }
8114  if(TrackElement.SpeedTag == 129) // vertical footbridge
8115  {
8116  // check top connection
8117  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8118  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8119  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8120  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8121  {
8122  Utilities->CallLogPop(550);
8123  return(false);
8124  }
8125  // check bottom connection
8126  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8127  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8128  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8129  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8130  {
8131  Utilities->CallLogPop(551);
8132  return(false);
8133  }
8134  }
8135  if(TrackElement.SpeedTag == 145) // vertical underpass
8136  {
8137  // check top connection
8138  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8139  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8140  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8141  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8142  {
8143  Utilities->CallLogPop(2114);
8144  return(false);
8145  }
8146  // check bottom connection
8147  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8148  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8149  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8150  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8151  {
8152  Utilities->CallLogPop(2115);
8153  return(false);
8154  }
8155  }
8156  if(TrackElement.SpeedTag == 130) // hor footbridge
8157  {
8158  // check left connection
8159  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8160  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8161  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8162  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8163  {
8164  Utilities->CallLogPop(552);
8165  return(false);
8166  }
8167  // check right connection
8168  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8169  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8170  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8171  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8172  {
8173  Utilities->CallLogPop(553);
8174  return(false);
8175  }
8176  }
8177  if(TrackElement.SpeedTag == 146) // hor u'pass
8178  {
8179  // check left connection
8180  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8181  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8182  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8183  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8184  {
8185  Utilities->CallLogPop(2116);
8186  return(false);
8187  }
8188  // check right connection
8189  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8190  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8191  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8192  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8193  {
8194  Utilities->CallLogPop(2117);
8195  return(false);
8196  }
8197  }
8198  Utilities->CallLogPop(554);
8199  return(true);
8200 }
8201 
8202 // ---------------------------------------------------------------------------
8203 
8204 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8205 /*
8206  return true if the SpeedTag present in the map at H & V
8207 */
8208 {
8209  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8210  AnsiString(SpeedTag));
8211  if(InactiveTrack2MultiMap.empty())
8212  {
8213  Utilities->CallLogPop(555);
8214  return(false);
8215  }
8216  THVPair HVPair(HLoc, VLoc);
8218  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8219  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8220 
8221  if(HVRange.first == HVRange.second)
8222  {
8223  Utilities->CallLogPop(556);
8224  return(false);
8225  }
8226  else
8227  {
8228  HVIt1 = HVRange.first;
8229  }
8230  TTrackElement Temp1, Temp2; // test
8231 
8232  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8233  if(--HVRange.second != HVRange.first)
8234  {
8235  HVIt2 = HVRange.second;
8236  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8237  }
8238  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8239  HVIt2->second).SpeedTag == SpeedTag)))
8240  {
8241  Utilities->CallLogPop(557);
8242  return(true);
8243  }
8244  else
8245  {
8246  Utilities->CallLogPop(558);
8247  return(false);
8248  }
8249 }
8250 
8251 // ---------------------------------------------------------------------------
8252 
8253 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8254 /*
8255  return true if the SpeedTag present in the map at H & V
8256 */
8257 {
8258  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8259  AnsiString(SpeedTag));
8260  if(TrackMap.empty())
8261  {
8262  Utilities->CallLogPop(559);
8263  return(false);
8264  }
8265  THVPair HVPair(HLoc, VLoc);
8266  TTrackMapIterator End = TrackMap.end();
8267  TTrackMapIterator It = End;
8268 
8269  It = TrackMap.find(HVPair);
8270  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8271  {
8272  Utilities->CallLogPop(560);
8273  return(true);
8274  }
8275  else
8276  {
8277  Utilities->CallLogPop(561);
8278  return(false);
8279  }
8280 }
8281 
8282 // ---------------------------------------------------------------------------
8283 
8284 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8285 {
8286 /*
8287  General:
8288  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8289  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8290  a NamedNonStationLocation.
8291  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8292  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8293  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8294  platform at that location).
8295 
8296  Linked named location elements are those explained in TTrack::TTrack()
8297 
8298  Detail:
8299  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8300  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8301  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8302  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8303  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8304  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8305 
8306  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8307  this function a single element should be in the List (normally from the user's selection but can also be from
8308  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8309  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8310  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8311  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8312  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8313  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8314  moves them into the Map. At the end all linked elements are in the Map.
8315 
8316  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8317  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8318  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8319 */
8320 
8321 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8322 // Display->FileDiagnostics(TestString);//test
8323 
8324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8325  AnsiString TestString1, TestString2; // test
8326 
8327  Track->LNDone2MultiMap.clear();
8328  if(LNPendingList.size() != 1)
8329  {
8330  throw Exception("LNPendingList size not 1 on entry");
8331  }
8332  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8333  while(!LNPendingList.empty())
8334  {
8335  CurrentElementNumber = LNPendingList.front();
8336  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8337  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8338  int H = CurrentElement->HLoc;
8339  int V = CurrentElement->VLoc;
8340  int Tag = CurrentElement->SpeedTag;
8341  if(Tag == 76) // top plat
8342  {
8343  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8344  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8345  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8346  for(int x = 0; x < 25; x++)
8347  {
8348  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8349  {
8350  LNPendingList.insert(LNPendingList.end(), NewElement);
8351  }
8352  }
8353  }
8354  else if(Tag == 77) // bot plat
8355  {
8356  for(int x = 0; x < 25; x++)
8357  {
8358  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8359  {
8360  LNPendingList.insert(LNPendingList.end(), NewElement);
8361  }
8362  }
8363  }
8364  else if(Tag == 78) // l plat
8365  {
8366  for(int x = 0; x < 25; x++)
8367  {
8368  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8369  {
8370  LNPendingList.insert(LNPendingList.end(), NewElement);
8371  }
8372  }
8373  }
8374  else if(Tag == 79) // r plat
8375  {
8376  for(int x = 0; x < 25; x++)
8377  {
8378  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8379  {
8380  LNPendingList.insert(LNPendingList.end(), NewElement);
8381  }
8382  }
8383  }
8384  else if(Tag == 96) // conc
8385  {
8386  for(int x = 0; x < 28; x++)
8387  {
8388  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8389  {
8390  LNPendingList.insert(LNPendingList.end(), NewElement);
8391  }
8392  }
8393  }
8394  else if(Tag == 129) // vert footbridge
8395  {
8396  for(int x = 0; x < 8; x++)
8397  {
8398  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8399  {
8400  LNPendingList.insert(LNPendingList.end(), NewElement);
8401  }
8402  }
8403  }
8404  else if(Tag == 130) // hor footbridge
8405  {
8406  for(int x = 0; x < 8; x++)
8407  {
8408  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8409  {
8410  LNPendingList.insert(LNPendingList.end(), NewElement);
8411  }
8412  }
8413  }
8414  else if(Tag == 131) // named location
8415  {
8416  for(int x = 0; x < 4; x++)
8417  {
8418  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8419  {
8420  LNPendingList.insert(LNPendingList.end(), NewElement);
8421  }
8422  }
8423  }
8424  else if(Tag == 145) // v u'pass
8425  {
8426  for(int x = 0; x < 8; x++)
8427  {
8428  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8429  {
8430  LNPendingList.insert(LNPendingList.end(), NewElement);
8431  }
8432  }
8433  }
8434  else if(Tag == 146) // h u'pass
8435  {
8436  for(int x = 0; x < 8; x++)
8437  {
8438  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8439  {
8440  LNPendingList.insert(LNPendingList.end(), NewElement);
8441  }
8442  }
8443  }
8444  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8445 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8446  if(AddingElements)
8447  {
8448  int HPos, VPos; // not used but needed for FindText function
8449  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8450  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8451  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8452  {
8453  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8454  if((ExistingName != "") && (ExistingName != LocationName))
8455  {
8456  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8457  {
8458  } // name not in LocationNameMultiMap, so don't erase from TextVector
8459  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8460  {
8461  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8462  {
8463  ;
8464  } // condition not used
8465 
8466  }
8467  }
8468  }
8469  }
8470  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8471  // track at that loc
8472  THVPair HVPair(H, V);
8473  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8474  LNDone2MultiMapEntry.first = HVPair;
8475  LNDone2MultiMapEntry.second = LNPendingList.front();
8476  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8477  LNPendingList.erase(LNPendingList.begin());
8478  }
8479 
8480 // search all name multimap for same name where corresponding active elements don't appear in
8481 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8482 
8483  TLocationNameMultiMapIterator SNIterator;
8484  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8485  bool FoundFlag, ErasedFlag = false;
8486 
8487  if(SNRange.first != SNRange.second)
8488  {
8489  SNRange.first--; // now pointing to before the first
8490  SNRange.second--; // now pointing to the last
8491  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8492  {
8493  // Same elements are in Done map as in name map
8494  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8495  {
8496  ErasedFlag = true;
8497  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8498  TVIt->LocationName = "";
8499  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8500  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8501  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8502  {
8503  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8504  if(FoundFlag)
8505  {
8506  TrackElementAt(20, Position).LocationName = "";
8507  TrackElementAt(21, Position).ActiveTrackElementName = "";
8508  }
8509  }
8510  // erase name in name map
8511 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8512  }
8513  }
8514  }
8515  if(ErasedFlag)
8516  {
8518  }
8519  if(TrackFinished)
8520  {
8522  }
8523 // set here as well as in LinkTrack so don't have to link track just because a name added
8524 // if track not finished then will be set when track validated
8525 
8526 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8527 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8528 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8529 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8530 // so the error would be seen.
8531 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8532  std::pair<AnsiString, char>TempMapPair;
8533 
8534  ContinuationNameMap.clear();
8535  for(int x = 0; x < Track->TrackVectorSize(); x++)
8536  {
8537  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8538  {
8539  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8540  TempMapPair.second = 'x'; // unused
8541  ContinuationNameMap.insert(TempMapPair);
8542  }
8543  }
8544 //end of addition
8545  CheckLocationNameMultiMap(1); // test
8546  Utilities->CallLogPop(562);
8547 }
8548 
8549 // ---------------------------------------------------------------------------
8550 
8551 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8552 /*
8553  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8554  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8555 */
8556 {
8557  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8558  AnsiString(SpeedTag));
8559  if(!NamedLocationElementAt(2, HLoc, VLoc))
8560  {
8561  Utilities->CallLogPop(948);
8562  return(false);
8563  }
8564  bool FoundFlag;
8565  int Position = -1;
8566  TIMPair IMPair;
8567 
8568  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8569  {
8570  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8571  if(FoundFlag)
8572  {
8573  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8574  {
8575  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8576  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8577  // don't allow duplicates in either list, or processing takes a lot longer
8578  {
8579  FoundElement = MapPos;
8580  Utilities->CallLogPop(563);
8581  return(true);
8582  }
8583  }
8584  }
8585  }
8586  else
8587  {
8588  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8589  if(FoundFlag)
8590  {
8591  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8592  {
8593  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8594  {
8595  FoundElement = IMPair.first;
8596  Utilities->CallLogPop(564);
8597  return(true);
8598  }
8599  }
8600  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8601  {
8602  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8603  {
8604  FoundElement = IMPair.second;
8605  Utilities->CallLogPop(565);
8606  return(true);
8607  }
8608  }
8609  }
8610  }
8611  Utilities->CallLogPop(566);
8612  return(false);
8613 }
8614 
8615 // ---------------------------------------------------------------------------
8616 
8617 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8618 /*
8619  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8620  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8621  with the new name
8622 */
8623 {
8624  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8625  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8626 
8627  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8628  int HLoc = TrackElement->HLoc;
8629  int VLoc = TrackElement->VLoc;
8630  bool FoundFlag;
8631 
8632  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8633  // only have timetable names for adjacent platforms & named locations
8634  {
8635  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8636  if(FoundFlag)
8637  {
8638  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8639  }
8640  }
8641  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8642 
8643  if(ErrorString != "")
8644  {
8645  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8646  }
8647  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8648  CheckLocationNameMultiMap(2); // test
8649  Utilities->CallLogPop(567);
8650 }
8651 
8652 // ---------------------------------------------------------------------------
8653 
8654 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8655 /*
8656  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8657 */
8658 {
8659  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8660  if(LNDone2MultiMap.empty())
8661  {
8662  Utilities->CallLogPop(568);
8663  return(false);
8664  }
8665  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8666 
8667  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8668  {
8669  if(LNDone2MultiMapIterator->second == MapPos)
8670  {
8671  Utilities->CallLogPop(569);
8672  return(true);
8673  }
8674  }
8675  Utilities->CallLogPop(570);
8676  return(false);
8677 }
8678 
8679 // ---------------------------------------------------------------------------
8680 
8681 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8682 /*
8683  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8684 */
8685 {
8686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8687  if(LNPendingList.empty())
8688  {
8689  Utilities->CallLogPop(571);
8690  return(false);
8691  }
8692  TLNPendingListIterator LNPendingListIterator;
8693 
8694  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8695  {
8696  if(*LNPendingListIterator == MapPos)
8697  {
8698  Utilities->CallLogPop(572);
8699  return(true);
8700  }
8701  }
8702  Utilities->CallLogPop(573);
8703  return(false);
8704 }
8705 
8706 // ---------------------------------------------------------------------------
8707 
8708 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8709 /*
8710  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8711 */
8712 {
8713  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8714  THVPair HVPair(HLoc, VLoc);
8715  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8716  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8717 
8718  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8719  {
8720  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8721  {
8722  Utilities->CallLogPop(574);
8723  return(true);
8724  }
8725  }
8726  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8727  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8728  {
8729  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8730  {
8731  Utilities->CallLogPop(575);
8732  return(true);
8733  }
8734  }
8735  Utilities->CallLogPop(576);
8736  return(false);
8737 }
8738 
8739 // ---------------------------------------------------------------------------
8740 
8741 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8742 {
8743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8744  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8745  {
8746  Utilities->CallLogPop(1953);
8747  return(true);
8748  }
8749  Utilities->CallLogPop(1954);
8750  return(false);
8751 }
8752 
8753 // ---------------------------------------------------------------------------
8754 
8755 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8756 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8757 //program and used when try to save as a .rly file
8758 {
8759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8762  if(LocationNameMultiMap.empty()) //no names so no duplicates
8763  {
8764  Utilities->CallLogPop(2254);
8765  return(false);
8766  }
8767  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8768  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8769  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8770  {
8772  {
8773  if(GiveMessage)
8774  {
8775  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8776  }
8777  Utilities->CallLogPop(2255);
8778  return(true);
8779  }
8780  }
8781  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8782  {
8783  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8784  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8785  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8786  {
8788  {
8789  if(GiveMessage)
8790  {
8791  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8792  }
8793  Utilities->CallLogPop(2256);
8794  return(true);
8795  }
8796  }
8797  }
8798  Utilities->CallLogPop(2257);
8799  return(false); //OK, no duplicates
8800 }
8801 
8802 // ---------------------------------------------------------------------------
8803 
8805 {
8806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8807  THVPair HVPair;
8808  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8809  //for use in the duplicate check
8810  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8811  {
8812  if(LNMMIt->second < 0) //active track element
8813  {
8814  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8815  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8816  }
8817  else //inactive track element
8818  {
8819  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8820  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8821  }
8822  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8823  }
8824  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8825 
8826  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8827  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8828  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8829 
8830  std::list<THVPair> HVLinkedList;
8831 
8832  //set the first value to true and add it to the list
8833  HVPairsLinkedMap.begin()->second = true;
8834  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8835  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8836  //examination
8837  THVPair HVPairUnderExamination;
8838  THVPairsLinkedMap::iterator HVPLMIt;
8839  THVPair HVPairNew;
8840  while(!HVLinkedList.empty())
8841  {
8842  HVPairUnderExamination = HVLinkedList.front();
8843  HVLinkedList.pop_front();
8844  HVPairNew.first = HVPairUnderExamination.first;
8845  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8846  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8847  if(HVPLMIt != HVPairsLinkedMap.end())
8848  {
8849  if(!HVPLMIt->second)
8850  {
8851  HVLinkedList.push_back(HVPLMIt->first);
8852  }
8853  HVPLMIt->second = true;
8854  }
8855  HVPairNew.first = HVPairUnderExamination.first - 1;
8856  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8857  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8858  if(HVPLMIt != HVPairsLinkedMap.end())
8859  {
8860  if(!HVPLMIt->second)
8861  {
8862  HVLinkedList.push_back(HVPLMIt->first);
8863  }
8864  HVPLMIt->second = true;
8865  }
8866  HVPairNew.first = HVPairUnderExamination.first;
8867  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8868  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8869  if(HVPLMIt != HVPairsLinkedMap.end())
8870  {
8871  if(!HVPLMIt->second)
8872  {
8873  HVLinkedList.push_back(HVPLMIt->first);
8874  }
8875  HVPLMIt->second = true;
8876  }
8877  HVPairNew.first = HVPairUnderExamination.first + 1;
8878  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8879  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8880  if(HVPLMIt != HVPairsLinkedMap.end())
8881  {
8882  if(!HVPLMIt->second)
8883  {
8884  HVLinkedList.push_back(HVPLMIt->first);
8885  }
8886  HVPLMIt->second = true;
8887  }
8888  }
8889 
8890  //at the end if any have a false bool then the name is duplicated so return false
8891  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8892  {
8893  if(!HVPLMIt->second)
8894  {
8895  Utilities->CallLogPop(2258);
8896  return(false);
8897  }
8898  }
8899  Utilities->CallLogPop(2259);
8900  return(true);
8901 }
8902 
8903 // ---------------------------------------------------------------------------
8904 
8905 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8906 /*
8907  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8908 */
8909 
8910 {
8911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8912  if(LocationName == "")
8913  {
8914  Utilities->CallLogPop(577);
8915  return(false);
8916  }
8917 // new for v0.2b
8918 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8920  {
8921  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8922  ActiveTrackElementNameMap.clear();
8923  for(unsigned int x = 0; x < TrackVector.size(); x++)
8924  {
8925  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8926  == ContinuationNameMap.end())
8927  {
8928  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8929  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8930  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8931  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8932  }
8933  }
8935  }
8936  Utilities->CallLogPop(578);
8937  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8938 // end of new section
8939 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8940 }
8941 
8942 // ---------------------------------------------------------------------------
8943 
8944 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8945 /*
8946  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8947  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8948  new names in the vectors.
8949 */
8950 {
8951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8952  bool FoundFlag, ErasedFlag = false;
8953  TLocationNameMultiMapIterator SNIterator;
8954  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8955 
8956  if(SNRange.first != SNRange.second)
8957  {
8958  ErasedFlag = true;
8959  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8960  {
8961  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8962  TVIt->LocationName = "";
8963  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8964  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8965  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8966  {
8967  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8968  if(FoundFlag)
8969  {
8970  TrackElementAt(25, Position).LocationName = "";
8971  TrackElementAt(26, Position).ActiveTrackElementName = "";
8972  }
8973  }
8974  }
8975  }
8976  if(ErasedFlag)
8977  {
8979  }
8980  CheckLocationNameMultiMap(3); // test
8981  Utilities->CallLogPop(579);
8982 }
8983 
8984 // ---------------------------------------------------------------------------
8985 
8986 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8987 /*
8988  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8989  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8990  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8991  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8992  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8993  naming up to date with the deletion or insertion.
8994 */
8995 {
8996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8997  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8998  LNPendingList.clear();
8999  AnsiString LocationName;
9000  int MapPos;
9001  bool FoundFlag = 0;
9002 
9003 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9004  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9005  if(FoundFlag)
9006  {
9007  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9008  if(LocationName != "")
9009  {
9010  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9011  EnterLocationName(13, LocationName, true);
9012  Utilities->CallLogPop(2251);
9013  return;
9014  }
9015  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9016  if(LocationName != "")
9017  {
9018  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9019  EnterLocationName(14, LocationName, true);
9020  Utilities->CallLogPop(2252);
9021  return;
9022  }
9023  }
9024 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9025 
9026  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9027  if(FoundFlag)
9028  {
9029  LocationName = TrackElementAt(1004, Position).LocationName;
9030  if(LocationName != "")
9031  {
9032  int ModifiedPosition = -1 - Position;
9033  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9034  EnterLocationName(15, LocationName, true);
9035  Utilities->CallLogPop(2253);
9036  return;
9037  }
9038  }
9039  if(SpeedTag == 76) // top plat
9040  {
9041  for(int x = 0; x < 25; x++)
9042  {
9043  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9044  {
9045  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9046  EnterLocationName(3, LocationName, true);
9047  break;
9048  }
9049  }
9050  }
9051  else if(SpeedTag == 77) // bot plat
9052  {
9053  for(int x = 0; x < 25; x++)
9054  {
9055  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9056  {
9057  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9058  EnterLocationName(4, LocationName, true);
9059  break;
9060  }
9061  }
9062  }
9063  else if(SpeedTag == 78) // l plat
9064  {
9065  for(int x = 0; x < 25; x++)
9066  {
9067  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9068  {
9069  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9070  EnterLocationName(5, LocationName, true);
9071  break;
9072  }
9073  }
9074  }
9075  else if(SpeedTag == 79) // r plat
9076  {
9077  for(int x = 0; x < 25; x++)
9078  {
9079  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9080  {
9081  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9082  EnterLocationName(6, LocationName, true);
9083  break;
9084  }
9085  }
9086  }
9087  else if(SpeedTag == 96) // conc
9088  {
9089  for(int x = 0; x < 28; x++)
9090  {
9091  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9092  {
9093  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9094  EnterLocationName(7, LocationName, true);
9095  break;
9096  }
9097  }
9098  }
9099  else if(SpeedTag == 129) // vert footbridge
9100  {
9101  for(int x = 0; x < 8; x++)
9102  {
9103  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9104  {
9105  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9106  EnterLocationName(8, LocationName, true);
9107  break;
9108  }
9109  }
9110  }
9111  else if(SpeedTag == 130) // hor footbridge
9112  {
9113  for(int x = 0; x < 8; x++)
9114  {
9115  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9116  {
9117  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9118  EnterLocationName(9, LocationName, true);
9119  break;
9120  }
9121  }
9122  }
9123  else if(SpeedTag == 145) // vert u'pass
9124  {
9125  for(int x = 0; x < 8; x++)
9126  {
9127  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9128  {
9129  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9130  EnterLocationName(11, LocationName, true);
9131  break;
9132  }
9133  }
9134  }
9135  else if(SpeedTag == 146) // hor u'pass
9136  {
9137  for(int x = 0; x < 8; x++)
9138  {
9139  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9140  {
9141  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9142  EnterLocationName(12, LocationName, true);
9143  break;
9144  }
9145  }
9146  }
9147  else if(SpeedTag == 131) // named location
9148  {
9149  for(int x = 0; x < 4; x++)
9150  {
9151  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9152  {
9153  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9154  EnterLocationName(10, LocationName, true);
9155  break;
9156  }
9157  }
9158  }
9159 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9160  Utilities->CallLogPop(580);
9161 }
9162 
9163 // ---------------------------------------------------------------------------
9164 
9165 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9166 /*
9167  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9168  true if a LocationName is found, and also returns the name and the adjusted vector position.
9169 */
9170 {
9171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9172  AnsiString(SpeedTag));
9173  bool FoundFlag;
9174  TIMPair IMPair;
9175  TTrackVectorIterator TempElement;
9176  int Position;
9177 
9178  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9179  if(FoundFlag)
9180  {
9181  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9182  {
9183  TempElement = InactiveTrackVector.begin() + IMPair.first;
9184  if(TempElement->LocationName != "")
9185  {
9186  LocationName = TempElement->LocationName;
9187  FoundElement = IMPair.first;
9188  Utilities->CallLogPop(581);
9189  return(true);
9190  }
9191  }
9192  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9193  {
9194  TempElement = InactiveTrackVector.begin() + IMPair.second;
9195  if(TempElement->LocationName != "")
9196  {
9197  LocationName = TempElement->LocationName;
9198  FoundElement = IMPair.second;
9199  Utilities->CallLogPop(582);
9200  return(true);
9201  }
9202  }
9203  }
9204  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9205  if(FoundFlag)
9206  {
9207  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9208  {
9209  TempElement = TrackVector.begin() + Position;
9210  if(TempElement->LocationName != "")
9211  {
9212  LocationName = TempElement->LocationName;
9213  FoundElement = -1 - Position;
9214  Utilities->CallLogPop(583);
9215  return(true);
9216  }
9217  }
9218  }
9219  Utilities->CallLogPop(584);
9220  return(false);
9221 }
9222 
9223 // ---------------------------------------------------------------------------
9224 
9225 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9226 {
9227 // check quantity in map & vectors match
9228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9229  unsigned int Count = 0;
9230 
9231  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9232  {
9233  Utilities->CallLogPop(2059);
9234  return;
9235  }
9236  AnsiString SName, TName, ErrorString;
9237 
9238  for(unsigned int x = 0; x < TrackVector.size(); x++)
9239  {
9240  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9241  {
9242  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9243  {
9244  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9245  AnsiString(Caller));
9246  }
9247  Count++;
9248  }
9249  }
9250  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9251  {
9252  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9253  {
9254  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9255  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9256  {
9257  throw Exception
9258  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9259  AnsiString(Caller));
9260  }
9261  Count++;
9262  }
9263  }
9264  if(LocationNameMultiMap.size() != Count)
9265  {
9266  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9267  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9268  }
9269 // check all entries in both vectors match entries in name multimap
9271 
9272  for(unsigned int x = 0; x < TrackVector.size(); x++)
9273  {
9274  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9275  {
9276  SName = TrackElementAt(1365, x).LocationName;
9277  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9278  if(ErrorString != "")
9279  {
9280  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9281  }
9282  if(SNIt->second != -1 - (int)x)
9283  {
9284  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9285  AnsiString(Caller));
9286  }
9287  }
9288  // check corresponding platform for all Timetable entries that aren't empty
9289  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9290  TIMPair IMPair;
9291  bool FoundFlag = false;
9292  if(TName != "")
9293  {
9294  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9295  if(FoundFlag)
9296  {
9297  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9299  {
9300  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9301  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9302  }
9303  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9304  {
9305  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9306  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9307  AnsiString(Caller));
9308  }
9309  }
9310  else
9311  {
9312  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9313  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9314  }
9315  }
9316  }
9317  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9318  {
9319  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9320  {
9321  SName = InactiveTrackElementAt(148, x).LocationName;
9322  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9323  if(ErrorString != "")
9324  {
9325  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9326  }
9327  if(SNIt->second != (int)x)
9328  {
9329  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9330  AnsiString(Caller));
9331  }
9332  }
9333  }
9334  Utilities->CallLogPop(585);
9335 }
9336 
9337 // ---------------------------------------------------------------------------
9338 
9340  AnsiString &ErrorString)
9341 {
9342 /*
9343  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9344  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9345  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9346 */
9347  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9348  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9349  ErrorString = "";
9350  bool FoundFlag = false;
9351  TLocationNameMultiMapIterator SNIterator;
9352  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9353 
9354  if(SNRange.first == SNRange.second)
9355  {
9356  ErrorString = "Error, Name " + LocationName + " not found in map";
9357  Utilities->CallLogPop(586);
9358  return(SNRange.first);
9359  }
9360  else
9361  {
9362  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9363  {
9364  if(SNIterator->second < 0)
9365  {
9366  int TVPos = -1 - SNIterator->second;
9367  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9368  if(TVIt == TrackElement)
9369  {
9370  FoundFlag = true;
9371  Utilities->CallLogPop(587);
9372  return(SNIterator);
9373  }
9374  }
9375  else
9376  {
9377  int ITVPos = SNIterator->second;
9378  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9379  if(ITVIt == TrackElement)
9380  {
9381  FoundFlag = true;
9382  Utilities->CallLogPop(588);
9383  return(SNIterator);
9384  }
9385  }
9386  }
9387  }
9388  if(!FoundFlag)
9389  {
9390  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9391  }
9392  Utilities->CallLogPop(589);
9393  return(SNIterator);
9394 }
9395 
9396 // ---------------------------------------------------------------------------
9397 
9398 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9399 {
9400 /*
9401  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9402  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9403 */
9404  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9405  TLocationNameMultiMapEntry LocationNameEntry;
9406 
9407  LocationNameEntry.first = NewName;
9408  LocationNameEntry.second = SNIterator->second;
9409  LocationNameMultiMap.erase(SNIterator);
9410  LocationNameMultiMap.insert(LocationNameEntry);
9411  Utilities->CallLogPop(590);
9412 }
9413 
9414 // ---------------------------------------------------------------------------
9415 
9417 {
9418 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9420  if(Position < 0) // footcrossing
9421  {
9422  int TruePos = -1 - Position;
9423  // new check at v0.2b
9424  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9425  {
9426  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9427  }
9428  Utilities->CallLogPop(591);
9429  return (TrackVector.begin() + TruePos);
9430  }
9431  else
9432  {
9433  // new check at v0.2b
9434  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9435  {
9436  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9437  }
9438  Utilities->CallLogPop(592);
9439  return (InactiveTrackVector.begin() + Position);
9440  }
9441 }
9442 
9443 // ---------------------------------------------------------------------------
9444 
9445 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9446 {
9447 /*
9448  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9449  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9450  LocationNameMultiMap.
9451 */
9452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9453  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9454  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9455 
9456  if(!InactiveTrack2MultiMap.empty())
9457  {
9458  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9459  InactiveTrack2MultiMapIterator++)
9460  {
9461  if(InactiveTrack2MultiMapIterator->second > VecPos)
9462  {
9463  InactiveTrack2MultiMapIterator->second--;
9464  }
9465  // can't be == VecPos as that position erased
9466  }
9467  }
9468  if(!LocationNameMultiMap.empty())
9469  {
9470  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9471  LocationNameMultiMapIterator++)
9472  {
9473  if(LocationNameMultiMapIterator->second < 0)
9474  {
9475  continue; // deal with TrackVectors separately
9476  }
9477  if(LocationNameMultiMapIterator->second > (int)VecPos)
9478  {
9479  LocationNameMultiMapIterator->second--;
9480  }
9481  }
9482  }
9483  Utilities->CallLogPop(593);
9484 }
9485 
9486 // ---------------------------------------------------------------------------
9487 
9488 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9489 {
9490 /*
9491  After an element has been erased from the track vector, all the later elements are moved down one. This function
9492  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9493  LocationNameMultiMap.
9494 */
9495  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9496  TTrackMapIterator TrackMapIterator;
9497  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9498 
9499  if(!TrackMap.empty())
9500  {
9501  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9502  {
9503  if(TrackMapIterator->second > VecPos)
9504  {
9505  TrackMapIterator->second--;
9506  }
9507  // can't be == VecPos as that position erased
9508  }
9509  }
9510  if(!LocationNameMultiMap.empty())
9511  {
9512  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9513  LocationNameMultiMapIterator++)
9514  {
9515  if(LocationNameMultiMapIterator->second >= 0)
9516  {
9517  continue; // deal with InactiveTrackVectors separately
9518  }
9519  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9520  // Val -1 -2 -3 -4 -5 -6 -7 -8
9521  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9522  {
9523  LocationNameMultiMapIterator->second++;
9524  }
9525  }
9526  }
9527  for(unsigned int x = 0; x < TrackVector.size(); x++)
9528  {
9529  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9530  if(TkEl.TrackType == GapJump)
9531  {
9532  // position 0 is the gap
9533  if(TkEl.Conn[0] == int(VecPos))
9534  {
9535  TkEl.Conn[0] = -1; // connected to a deleted gap
9536  continue;
9537  }
9538  if(TkEl.Conn[0] > int(VecPos))
9539  {
9540  TkEl.Conn[0]--;
9541  }
9542  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9543  {
9544  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9545  {
9546  TkEl.Conn[0] = -1;
9547  }
9548  }
9549  }
9550  }
9551  Utilities->CallLogPop(1433);
9552 }
9553 
9554 // ---------------------------------------------------------------------------
9555 
9557 /*
9558  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9559  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9560  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9561 */
9562 {
9563  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9564  LocationNameMultiMap.clear();
9565  TLocationNameMultiMapEntry LocationNameEntry;
9566  TTrackElement TrackElement;
9567 
9568  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9569  {
9570  TrackElement = TrackElementAt(1376, TVPos);
9571  if(TrackElement.FixedNamedLocationElement)
9572  {
9573  LocationNameEntry.first = TrackElement.LocationName;
9574  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9575  LocationNameMultiMap.insert(LocationNameEntry);
9576  }
9577  }
9578 
9579  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9580  {
9581  TrackElement = InactiveTrackElementAt(149, ITVPos);
9582  if(TrackElement.FixedNamedLocationElement)
9583  {
9584  LocationNameEntry.first = TrackElement.LocationName;
9585  LocationNameEntry.second = ITVPos;
9586  LocationNameMultiMap.insert(LocationNameEntry);
9587  }
9588  }
9589  Utilities->CallLogPop(594);
9590 }
9591 
9592 // ---------------------------------------------------------------------------
9593 
9595 // Return true if there is a named location present in the railway
9596 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9597 {
9598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9599  TTrackVectorIterator ITVI;
9600 
9601  if(InactiveTrackVector.empty())
9602  {
9603  Utilities->CallLogPop(1343);
9604  return(false);
9605  }
9606  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9607  {
9608  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9609  {
9610  Utilities->CallLogPop(1404);
9611  return(true);
9612  }
9613  }
9614  Utilities->CallLogPop(1344);
9615  return(false);
9616 }
9617 
9618 // ---------------------------------------------------------------------------
9619 
9621 /*
9622  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9623 */
9624 {
9625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9626 // ResetDistanceElements(6);
9627  for(unsigned int x = 0; x < TrackVector.size(); x++)
9628  {
9629  TTrackElement &TE = TrackElementAt(718, x);
9632  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9633  {
9636  }
9637  }
9638 /* old function
9639  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9640  {
9641  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9642  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9643  }
9644  else
9645  {
9646  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9647  }
9648  }
9649 */
9650  Utilities->CallLogPop(617);
9651 }
9652 
9653 // ---------------------------------------------------------------------------
9654 
9655 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9656 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9657 {
9658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9659  for(unsigned int x = 0; x < TrackVector.size(); x++)
9660  {
9661  TTrackElement TempElement = TrackElementAt(1377, x);
9662  if(TempElement.Length01 > -1)
9663  {
9664  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9665  }
9666  if(TempElement.Length23 > -1)
9667  {
9668  MarkOneLength(2, TempElement, false, Disp);
9669  }
9670  }
9671  Disp->Update();
9672  Utilities->CallLogPop(618);
9673 }
9674 
9675 // ---------------------------------------------------------------------------
9676 
9677 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9678 /*
9679  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9680  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9681  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9682  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9683  track as indicated by FirstTrack (true for track01 & false for track23).
9684 */
9685 {
9686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9687  AnsiString((short)FirstTrack));
9688  bool LengthDifferent = false, SpeedDifferent = false;
9689 
9690  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9691  {
9692  Utilities->CallLogPop(619);
9693  return;
9694  }
9695  int EXArray[16][2] =
9696  {{4, 6}, {2, 8}, // horizontal & vertical
9697  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9698  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9699  {1, 9}, {3, 7}}; // forward & reverse diagonals
9700 
9701  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9702  Graphics::TBitmap *Bitmap;
9703 
9704  if(FirstTrack)
9705  {
9706  InLink = TrackElement.Link[0];
9707  OutLink = TrackElement.Link[1];
9708  }
9709  else
9710  {
9711  InLink = TrackElement.Link[2];
9712  OutLink = TrackElement.Link[3];
9713  }
9714  for(int x = 0; x < 16; x++)
9715  {
9716  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9717  {
9718  Index = x;
9719  }
9720  }
9721  if(Index == -1)
9722  {
9723  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9724  }
9725 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9726  the graphic for each of which is different because of the shape of the overbridge. The basic
9727  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9728  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9729  int BrEXArray[24][2] = {
9730  {4,6},{2,8},{1,9},{3,7},
9731  {1,9},{3,7},{1,9},{3,7},
9732  {2,8},{4,6},{2,8},{4,6}
9733 */
9734  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9735  {
9736  if(Index == 1)
9737  {
9738  if(TrackElement.SpeedTag == 49)
9739  {
9740  BrNum = 1 + 16;
9741  }
9742  else if(TrackElement.SpeedTag == 54)
9743  {
9744  BrNum = 8 + 16;
9745  }
9746  else if(TrackElement.SpeedTag == 55)
9747  {
9748  BrNum = 10 + 16;
9749  }
9750  }
9751  else if(Index == 0)
9752  {
9753  if(TrackElement.SpeedTag == 48)
9754  {
9755  BrNum = 0 + 16;
9756  }
9757  else if(TrackElement.SpeedTag == 58)
9758  {
9759  BrNum = 11 + 16;
9760  }
9761  else if(TrackElement.SpeedTag == 59)
9762  {
9763  BrNum = 9 + 16;
9764  }
9765  }
9766  else if(Index == 14)
9767  {
9768  if(TrackElement.SpeedTag == 50)
9769  {
9770  BrNum = 2 + 16;
9771  }
9772  else if(TrackElement.SpeedTag == 52)
9773  {
9774  BrNum = 4 + 16;
9775  }
9776  else if(TrackElement.SpeedTag == 57)
9777  {
9778  BrNum = 6 + 16;
9779  }
9780  }
9781  else if(Index == 15)
9782  {
9783  if(TrackElement.SpeedTag == 51)
9784  {
9785  BrNum = 3 + 16;
9786  }
9787  else if(TrackElement.SpeedTag == 53)
9788  {
9789  BrNum = 7 + 16;
9790  }
9791  else if(TrackElement.SpeedTag == 56)
9792  {
9793  BrNum = 5 + 16;
9794  }
9795  }
9796  }
9797  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9798  {
9799  GrNum = BrNum;
9800  }
9801  else
9802  {
9803  GrNum = Index;
9804  }
9805  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9806  {
9807  if(GrNum > 15) // underbridge
9808  {
9809  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9810  }
9811  else
9812  {
9813  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9814  }
9815  if(TrackElement.SpeedTag == 64)
9816  {
9817  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9818  }
9819  if(TrackElement.SpeedTag == 65)
9820  {
9822  }
9823  if(TrackElement.SpeedTag == 66)
9824  {
9826  }
9827  if(TrackElement.SpeedTag == 67)
9828  {
9830  }
9831  if(TrackElement.SpeedTag == 80)
9832  {
9833  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9834  }
9835  if(TrackElement.SpeedTag == 81)
9836  {
9838  }
9839  if(TrackElement.SpeedTag == 82)
9840  {
9842  }
9843  if(TrackElement.SpeedTag == 83)
9844  {
9846  }
9847  if(TrackElement.SpeedTag == 84)
9848  {
9850  }
9851  if(TrackElement.SpeedTag == 85)
9852  {
9854  }
9855  if(TrackElement.SpeedTag == 86)
9856  {
9858  }
9859  if(TrackElement.SpeedTag == 87)
9860  {
9862  }
9863  if(TrackElement.SpeedTag == 129)
9864  {
9865  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9866  }
9867  if(TrackElement.SpeedTag == 130)
9868  {
9870  }
9871  }
9872 
9873  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9874  {
9875  if(GrNum > 15) // underbridge
9876  {
9877  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9878  }
9879  else
9880  {
9881  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9882  }
9883  if(TrackElement.SpeedTag == 64)
9884  {
9885  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9886  }
9887  if(TrackElement.SpeedTag == 65)
9888  {
9889  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9890  }
9891  if(TrackElement.SpeedTag == 66)
9892  {
9893  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9894  }
9895  if(TrackElement.SpeedTag == 67)
9896  {
9897  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9898  }
9899  if(TrackElement.SpeedTag == 80)
9900  {
9901  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9902  }
9903  if(TrackElement.SpeedTag == 81)
9904  {
9905  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9906  }
9907  if(TrackElement.SpeedTag == 82)
9908  {
9909  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9910  }
9911  if(TrackElement.SpeedTag == 83)
9912  {
9913  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9914  }
9915  if(TrackElement.SpeedTag == 84)
9916  {
9917  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9918  }
9919  if(TrackElement.SpeedTag == 85)
9920  {
9921  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9922  }
9923  if(TrackElement.SpeedTag == 86)
9924  {
9925  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9926  }
9927  if(TrackElement.SpeedTag == 87)
9928  {
9929  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9930  }
9931  if(TrackElement.SpeedTag == 129)
9932  {
9933  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9934  }
9935  if(TrackElement.SpeedTag == 130)
9936  {
9937  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9938  }
9939  }
9940 
9941  else // SpeedDifferent only: red - use non sig graphics
9942  {
9943  if(GrNum > 15) // underbridge
9944  {
9945  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9946  }
9947  else
9948  {
9949  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9950  }
9951  if(TrackElement.SpeedTag == 64)
9952  {
9953  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9954  }
9955  if(TrackElement.SpeedTag == 65)
9956  {
9958  }
9959  if(TrackElement.SpeedTag == 66)
9960  {
9962  }
9963  if(TrackElement.SpeedTag == 67)
9964  {
9966  }
9967  if(TrackElement.SpeedTag == 80)
9968  {
9969  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9970  }
9971  if(TrackElement.SpeedTag == 81)
9972  {
9974  }
9975  if(TrackElement.SpeedTag == 82)
9976  {
9978  }
9979  if(TrackElement.SpeedTag == 83)
9980  {
9982  }
9983  if(TrackElement.SpeedTag == 84)
9984  {
9986  }
9987  if(TrackElement.SpeedTag == 85)
9988  {
9990  }
9991  if(TrackElement.SpeedTag == 86)
9992  {
9994  }
9995  if(TrackElement.SpeedTag == 87)
9996  {
9998  }
9999  if(TrackElement.SpeedTag == 129)
10000  {
10001  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10002  }
10003  if(TrackElement.SpeedTag == 130)
10004  {
10006  }
10007  }
10008  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10009  Utilities->CallLogPop(620);
10010 }
10011 
10012 // ---------------------------------------------------------------------------
10013 
10014 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10015 /* FirstTrack = LinkPos's 0 & 1
10016  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10017 */
10018 {
10019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10020  AnsiString((short)FirstTrack));
10021  LengthDifferent = false;
10022  SpeedDifferent = false;
10023  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10024  {
10025  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10026  {
10027  LengthDifferent = true;
10028  }
10029  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10030  {
10031  SpeedDifferent = true;
10032  }
10033  if(LengthDifferent || SpeedDifferent)
10034  {
10035  Utilities->CallLogPop(625);
10036  return(false);
10037  }
10038  Utilities->CallLogPop(626);
10039  return(true);
10040  }
10041 
10042  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10043  {
10044  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10045  {
10046  LengthDifferent = true;
10047  }
10048  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10049  {
10050  SpeedDifferent = true;
10051  }
10052  if(LengthDifferent || SpeedDifferent)
10053  {
10054  Utilities->CallLogPop(627);
10055  return(false);
10056  }
10057  Utilities->CallLogPop(628);
10058  return(true);
10059  }
10060 
10061  else // any other 1 track element, including platforms being present
10062  {
10063  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10064  {
10065  LengthDifferent = true;
10066  }
10067  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10068  {
10069  SpeedDifferent = true;
10070  }
10071  if(LengthDifferent || SpeedDifferent)
10072  {
10073  Utilities->CallLogPop(629);
10074  return(false);
10075  }
10076  Utilities->CallLogPop(630);
10077  return(true);
10078  }
10079 }
10080 
10081 // ---------------------------------------------------------------------------
10082 
10083 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10084 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10085 {
10086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10087  AnsiString(VLoc));
10088  bool FoundFlag;
10089  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10090 
10091  if(!FoundFlag)
10092  {
10093  Utilities->CallLogPop(633);
10094  return(false);
10095  }
10096  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10097  {
10098  Utilities->CallLogPop(634);
10099  return(true); // only need to check first since if second is a platform the the first must be too
10100  }
10101  else
10102  {
10103  Utilities->CallLogPop(635);
10104  return(false);
10105  }
10106 }
10107 
10108 // ---------------------------------------------------------------------------
10109 
10110 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10111 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10112 {
10113  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10114  AnsiString(VLoc));
10115  bool FoundFlag;
10116  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10117 
10118  if(!FoundFlag)
10119  {
10120  Utilities->CallLogPop(636);
10121  return(false);
10122  }
10124  {
10125  Utilities->CallLogPop(637);
10126  return(true); // only need to check first since only one used for NamedNonStationLocations
10127  }
10128  else
10129  {
10130  Utilities->CallLogPop(638);
10131  return(false);
10132  }
10133 }
10134 
10135 // ---------------------------------------------------------------------------
10136 
10138 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10139  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10140  the front of train stop points for each direction.
10141  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10142  end (unless buffers at one or both ends in which case stop points are the end elements).
10143  Note that for a single element the stop point is the element itself (formula doesn't apply).
10144  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10145  repeating the procedure for every element. At the end all unused values are returned to -1.
10146  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10147 */
10148 {
10149  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10150  TTrackElement TempElement, StartElement;
10151  AnsiString TempName;
10152  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10153  bool ForwardSet, ReverseSet;
10154 
10155  for(unsigned int x = 0; x < TrackVector.size(); x++)
10156  {
10159  }
10160  for(unsigned int x = 0; x < TrackVector.size(); x++)
10161  {
10162  ForwardSet = false;
10163  ReverseSet = false;
10164  TempElement = TrackElementAt(1380, x);
10165  VecPos = x;
10166  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10167  // 2nd condition incl so don't re-examine elements with stop links set to 5
10168  {
10169  TempName = TempElement.ActiveTrackElementName;
10170  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10171  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10172  // an element linked at both ends where both links are also named elements
10173  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10174  {
10175  continue; // looking for an end element so skip this one
10176  }
10177  else // reached one end
10178  {
10179  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10180  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10181  // single named element linked at both ends
10182  {
10183  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10184  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10185  continue;
10186  }
10187  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10188  // single named buffer element (LinkPos 1 is the non-buffer end)
10189  {
10190  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10191  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10192  continue;
10193  }
10194  else
10195  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10196  // and platforms always on straight (conns 0 & 1) section of points
10197  {
10198  for(int y = 0; y < 2; y++)
10199  {
10200  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10201  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10202 /* TTrackElement Temp1 = TempElement;
10203  ***********New section, compiles but not checked - does bit below need to be else if?
10204  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10205  {
10206  //search along Dir direction until find other end, skip if Dir facing buffer end
10207  int NewDir = Dir;
10208  int NewVecPos;
10209  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10210  {
10211  NewVecPos = Temp1.Conn[NewDir];
10212  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10213  Temp1 = TrackElementAt(601, NewVecPos);
10214  }
10215  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10216  {
10217  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10218  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10219  }
10220  }
10221  ***************
10222 */
10223  // end may be linked at both ends but only one link named, or buffer with linked element named
10224  // if a buffer then the named linkpos has to be 1
10225  // already dealt with all types of single element so at least 2 linked named element
10226  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10227  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10228  {
10229  StartElement = TempElement;
10230  StartVecPos = VecPos;
10231  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10232  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10233  EntryPos = 1 - Dir;
10234  StartEntryPos = 1 - Dir;
10235  Count = 1;
10236  // work along named elements until find the other end
10237  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10238  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10239  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10240  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10241  // all stop link pos's are set to 5
10242  {
10243  VecPos = TempElement.Conn[1 - EntryPos];
10244  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10245  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10246  EntryPos = TempEntryPos;
10247  Count++;
10248  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10249  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10250  }
10251  // here when reached other end, maybe buffers, continuation or last named linked element
10252  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10253  // terminal station, set end elements as stop elements
10254  {
10255  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10256  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10257  continue;
10258  }
10259  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10260  // terminal station, set end elements as stop elements
10261  {
10262  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10263  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10264  continue;
10265  }
10266  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10267  // NonStationLocation so set end elements as stop elements
10268  {
10269  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10270  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10271  continue;
10272  }
10273  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10274  ForwardNumber = ((Count + 1) / 2) + 1;
10275  ReverseNumber = (Count - ForwardNumber) + 1;
10276  Count = 1; // starting value
10277  EntryPos = 1 - Dir;
10278  TempElement = StartElement;
10279  VecPos = StartVecPos;
10280  if(Count == ForwardNumber)
10281  {
10282  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10283  ForwardSet = true;
10284  }
10285  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10286  {
10287  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10288  ReverseSet = true;
10289  }
10290  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10291  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10292  {
10293  VecPos = TempElement.Conn[1 - EntryPos];
10294  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10295  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10296  EntryPos = TempEntryPos;
10297  Count++;
10298  if(Count == ForwardNumber)
10299  {
10300  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10301  ForwardSet = true;
10302  }
10303  if(Count == ReverseNumber)
10304  {
10305  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10306  ReverseSet = true;
10307  }
10308  }
10309  }
10310  }
10311  }
10312  }
10313  }
10314  }
10315  for(unsigned int x = 0; x < TrackVector.size(); x++)
10316  {
10317  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10318  {
10320  }
10321  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10322  {
10324  }
10325  }
10326  Utilities->CallLogPop(639);
10327 }
10328 
10329 // ---------------------------------------------------------------------------
10330 
10331 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10332 {
10333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10334  TTrackElement Next;
10335 
10337  while(ReturnNextInactiveTrackElement(1, Next))
10338  {
10339  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10340  {
10341  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10342  // need striped graphics
10343  {
10344  if(Next.SpeedTag == 76)
10345  {
10346  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10347  }
10348  else if(Next.SpeedTag == 77)
10349  {
10350  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10351  }
10352  else if(Next.SpeedTag == 78)
10353  {
10354  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10355  }
10356  else if(Next.SpeedTag == 79)
10357  {
10358  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10359  }
10360  else if(Next.SpeedTag == 96)
10361  {
10362  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10363  }
10364  else if(Next.SpeedTag == 131)
10365  {
10366  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10367  }
10368  }
10369  else
10370  {
10371  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10372  }
10373  }
10374  }
10375 
10376  NextTrackElementPtr = TrackVector.begin();
10377  while(ReturnNextTrackElement(1, Next))
10378  {
10379  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10380  {
10381  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10382  {
10383  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10384  {
10385  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10386  }
10387  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10388  {
10389  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10390  }
10391  }
10392  else
10393  {
10394  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10395  }
10396  }
10397  }
10398  Disp->Update();
10399  Utilities->CallLogPop(640);
10400 }
10401 
10402 // ---------------------------------------------------------------------------
10403 
10404 void TTrack::PlotSmallRedGap(int Caller)
10405 {
10406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10408  Utilities->CallLogPop(1346);
10409 }
10410 
10411 // ---------------------------------------------------------------------------
10412 
10413 void TTrack::TrackClear(int Caller)
10414 {
10415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10416  TrackVector.clear();
10417  InactiveTrackVector.clear();
10418  TrackMap.clear();
10420  if(TextHandler->TextVector.size() == 0)
10421  {
10422  Display->DisplayOffsetH = 0;
10423  Display->DisplayOffsetV = 0;
10430  HLocMin = 2000000000;
10431  HLocMax = -2000000000;
10432  VLocMin = 2000000000;
10433  VLocMax = -2000000000;
10434  }
10435  else
10436  {
10437  CalcHLocMinEtc(4);
10438  }
10439  Utilities->CallLogPop(1347);
10440 }
10441 
10442 // ---------------------------------------------------------------------------
10443 
10444 void TTrack::CalcHLocMinEtc(int Caller)
10445 {
10446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10447  HLocMin = 2000000000;
10448  VLocMin = 2000000000;
10449  HLocMax = -2000000000;
10450  VLocMax = -2000000000;
10451  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10452  {
10453  if(TrackElementAt(1385, x).SpeedTag == 0)
10454  {
10455  continue; // skip erase elements or would interfere with Min & Max values
10456  }
10457  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10458  {
10459  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10460  }
10461  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10462  {
10463  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10464  }
10465  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10466  {
10467  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10468  }
10469  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10470  {
10471  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10472  }
10473  }
10474  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10475  {
10476  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10477  {
10478  continue; // shouldn't be any inactive erase elements but include anyway
10479  }
10480  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10481  {
10482  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10483  }
10484  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10485  {
10486  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10487  }
10488  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10489  {
10490  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10491  }
10492  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10493  {
10494  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10495  }
10496  }
10497  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10498  {
10499 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10500  will fail as x will exceed the maximum value
10501  if(TextHandler->TextPtrAt(, x)->TextString == "")
10502  {
10503  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10504  }
10505 */
10506  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10507  if((TextH / 16) - 1 < HLocMin)
10508  {
10509  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10510  }
10511  if((TextH / 16) + 1 > HLocMax)
10512  {
10513  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10514  }
10515  if((TextV / 16) - 1 < VLocMin)
10516  {
10517  VLocMin = (TextV / 16) - 1;
10518  }
10519  if((TextV / 16) + 1 > VLocMax)
10520  {
10521  VLocMax = (TextV / 16) + 1;
10522  }
10523  }
10524  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10525  {
10526  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10527  {
10528  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10529  }
10530  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10531  {
10532  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10533  }
10534  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10535  {
10536  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10537  }
10538  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10539  {
10540  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10541  }
10542  }
10543 
10544  Utilities->CallLogPop(641);
10545 }
10546 
10547 // ---------------------------------------------------------------------------
10548 
10549 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10550  bool &UserGraphicFoundFlag)
10551 {
10552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10553  TUserGraphicVector::iterator UserGraphicPtr;
10554 
10555  UserGraphicFoundFlag = false;
10556  if(!UserGraphicVector.empty())
10557  {
10558  int x = UserGraphicVector.size();
10559  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10560  {
10561  x--;
10562  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10563  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10564  {
10565  UserGraphicItem = x;
10566  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10567  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10568  UserGraphicFoundFlag = true;
10569  Utilities->CallLogPop(2177);
10570  return;
10571  } // if ....
10572 
10573  } // for UserGraphicPtr...
10574  } // if !UserGraphicVector...
10575 
10576  Utilities->CallLogPop(2197);
10577 }
10578 
10579 // ---------------------------------------------------------------------------
10580 
10582 {
10583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10584  TrackElement.LogTrack(11));
10585  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10586  int SpeedTag = TrackElement.SpeedTag;
10587 
10588  if(SpeedTag < 1)
10589  {
10590  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10591  }
10592  switch(SpeedTag)
10593  {
10594  case 76: // t platform
10595  GraphicOutput = RailGraphics->gl76Striped;
10596  break;
10597 
10598  case 77: // h platform
10599  GraphicOutput = RailGraphics->bm77Striped;
10600  break;
10601 
10602  case 78: // v platform
10603  GraphicOutput = RailGraphics->bm78Striped;
10604  break;
10605 
10606  case 79: // r platform
10607  GraphicOutput = RailGraphics->gl79Striped;
10608  break;
10609 
10610  case 96: // concourse
10611  GraphicOutput = RailGraphics->ConcourseStriped;
10612  break;
10613 
10614  case 129: // v footbridge
10615  GraphicOutput = RailGraphics->gl129Striped;
10616  break;
10617 
10618  case 130: // h footbridge
10619  GraphicOutput = RailGraphics->gl130Striped;
10620  break;
10621 
10622  case 131: // non-station named loc
10623  GraphicOutput = RailGraphics->bmNameStriped;
10624  break;
10625 
10626  case 145: // v u'pass
10627  GraphicOutput = RailGraphics->gl145Striped;
10628  break;
10629 
10630  case 146: // h u'pass
10631  GraphicOutput = RailGraphics->gl146Striped;
10632  break;
10633 
10634  default:
10635  GraphicOutput = TrackElement.GraphicPtr;
10636  break;
10637  }
10638  Utilities->CallLogPop(642);
10639  return(GraphicOutput);
10640 }
10641 
10642 // ---------------------------------------------------------------------------
10643 
10645 {
10646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10647  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10648  {
10649 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10650  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10651  }
10652  Utilities->CallLogPop(643);
10653  return(TrackVector.at(At));
10654 }
10655 
10656 // ---------------------------------------------------------------------------
10657 
10659 {
10660  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10661  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10662  {
10663  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10664  " in InactiveTrackElementAt");
10665  }
10666  Utilities->CallLogPop(644);
10667  return(InactiveTrackVector.at(At));
10668 }
10669 
10670 // ---------------------------------------------------------------------------
10671 
10672 bool TTrack::BlankElementAt(int Caller, int At) const
10673 {
10674  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10675  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10676  {
10677  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10678  }
10679  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10680  {
10681  Utilities->CallLogPop(645);
10682  return(true);
10683  }
10684  else
10685  {
10686  Utilities->CallLogPop(646);
10687  return(false);
10688  }
10689 }
10690 
10691 // ---------------------------------------------------------------------------
10692 
10693 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10694 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10695  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10696  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10697  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10698  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10699 */
10700 {
10701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10702  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10703  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10704  TLocationNameMultiMapIterator SNIterator;
10705  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10706 
10707  if(SNRange.first == SNRange.second)
10708  {
10709  Utilities->CallLogPop(972);
10710  return(false); // should have been caught earlier but include for completeness
10711  }
10712  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10713  {
10714  if(SNIterator->second < 0)
10715  {
10716  continue; // exclude footcrossings
10717  }
10718  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10719  if(InactiveElement.TrackType == Concourse)
10720  {
10721  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10722  }
10723  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10724  {
10725  continue; // only interested in locations where ActiveTrackElementName may be set
10726  }
10727  THVPair HVPair;
10728  HVPair.first = InactiveElement.HLoc;
10729  HVPair.second = InactiveElement.VLoc;
10730  if(TrackMap.find(HVPair) == TrackMap.end())
10731  {
10732  throw Exception
10733  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10734  }
10735  int TVPos = TrackMap.find(HVPair)->second;
10736  FirstNamedElement = TrackElementAt(560, TVPos);
10737  // first check linked on both sides, skip the check if not
10738  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10739  {
10740  continue;
10741  }
10742  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10743  // ActiveTrackElementNames are points and excluding trailing connections for points
10744  FirstNamedExitPos = 0;
10745  {
10746  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10747  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10748  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10749  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10750  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10751  {
10752  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10753  {
10754  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10755  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10756  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10757  // success, now check FirstNamedElement link not trailing points & if so all OK
10758  {
10759  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10760  {
10761  Utilities->CallLogPop(1002);
10762  return(true);
10763  }
10764  }
10765  }
10766  }
10767  }
10768  // failed, try link 1
10769  FirstNamedExitPos = 1;
10770  {
10771  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10772  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10773  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10774  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10775  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10776  {
10777  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10778  {
10779  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10780  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10781  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10782  // success, now check FirstNamedElement link not trailing points & if so all OK
10783  {
10784  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10785  {
10786  Utilities->CallLogPop(1003);
10787  return(true);
10788  }
10789  }
10790  }
10791  }
10792  }
10793  }
10794  Utilities->CallLogPop(1004);
10795  return(false);
10796 }
10797 
10798 // ---------------------------------------------------------------------------
10799 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10800  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10801 // for success need two linked named location elements, so that one element of each train can be at the location
10802 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10803 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10804 // the two trains will occupy these 4 elements
10805 // All are track vector positions, all but the input being references and set within the function.
10806 {
10807 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10808  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10809  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10810  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10811  splitting.
10812 */
10813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10814  AnsiString(FirstNamedElementPos));
10815  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10816  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10817 
10818  SecondNamedElementPos = -1;
10819  FirstNamedLinkedElementPos = -1;
10820  SecondNamedLinkedElementPos = -1;
10821  TLocationNameMultiMapIterator SNIterator;
10822  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10823 
10824  if(SNRange.first == SNRange.second) // i.e. location name not in map
10825  {
10826  Utilities->CallLogPop(1005);
10827  return(false); // should have been caught earlier but include for completeness
10828  }
10829  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10830  {
10831  if(SNIterator->second < 0)
10832  {
10833  continue; // exclude footcrossings
10834  }
10835  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10836  if(InactiveElement.TrackType == Concourse)
10837  {
10838  continue; // only interested in locations where ActiveTrackElementName may be set
10839  }
10840  THVPair HVPair;
10841  HVPair.first = InactiveElement.HLoc;
10842  HVPair.second = InactiveElement.VLoc;
10843  if(TrackMap.find(HVPair) == TrackMap.end())
10844  {
10845  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10846  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10847  // then it won't be found in TrackMap but it's still legitimate.
10848  {
10849  continue;
10850  }
10851  else // for anything else throw the error
10852  {
10853  throw Exception
10854  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10855  );
10856  }
10857  }
10858  int TVPos = TrackMap.find(HVPair)->second;
10859  if(TVPos != FirstNamedElementPos)
10860  {
10861  continue; // looking for an exact match
10862  }
10863  FirstNamedElement = TrackElementAt(567, TVPos);
10864  // first check linked on both sides, skip the check if not
10865  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10866  {
10867  continue;
10868  }
10869  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10870  // ActiveTrackElementNames are points and excluding trailing connections for points
10871  FirstNamedExitPos = 0;
10872  {
10873  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10874  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10875  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10876  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10877  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10878  {
10879  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10880  {
10881  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10882  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10883  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10884  // success, now check FirstNamedElement link not trailing points & if so all OK
10885  {
10886  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10887  {
10888  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10889  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10890  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10891  Utilities->CallLogPop(1006);
10892  return(true);
10893  }
10894  }
10895  }
10896  }
10897  }
10898  // failed, try link 1
10899  FirstNamedExitPos = 1;
10900  {
10901  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10902  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10903  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10904  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10905  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10906  {
10907  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10908  {
10909  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10910  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10911  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10912  // success, now check FirstNamedElement link not trailing points & if so all OK
10913  {
10914  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10915  {
10916  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10917  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10918  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10919  Utilities->CallLogPop(1007);
10920  return(true);
10921  }
10922  }
10923  }
10924  }
10925  }
10926  }
10927  Utilities->CallLogPop(1008);
10928  return(false);
10929 }
10930 
10931 // ---------------------------------------------------------------------------
10932 
10933 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10934 {
10935  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10936  TLocationNameMultiMapIterator SNIterator;
10937  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10938 
10939  if(SNRange.first != SNRange.second)
10940  {
10941  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10942  {
10943  if(SNIterator->second < 0)
10944  {
10945  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10946  }
10947  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10948  SNIterator->second).TrackType == NamedNonStationLocation))
10949  {
10950  Utilities->CallLogPop(1121);
10951  return(true);
10952  }
10953  }
10954  }
10955  Utilities->CallLogPop(848);
10956  return(false);
10957 }
10958 
10959 // ---------------------------------------------------------------------------
10960 
10961 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10962 {
10963 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10965  "," + AnsiString(SpeedTag));
10966  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10967  {
10968  Utilities->CallLogPop(949);
10969  return(false);
10970  }
10971  bool FoundFlag;
10972  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10973 
10974  if(!FoundFlag)
10975  {
10976  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10977  }
10978  TTrackElement IAElement;
10979 
10980  if(SpeedTag == 68) // top sig
10981  {
10982  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10983  {
10984  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10985  {
10986  IAElement = InactiveTrackElementAt(50, IMPair.first);
10987  }
10988  else
10989  {
10990  IAElement = InactiveTrackElementAt(51, IMPair.second);
10991  }
10992  if(IAElement.LocationName == "")
10993  {
10994 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10995  SignalPlatformGraphic = RailGraphics->gl76Striped;
10996  }
10997  else
10998  {
10999 // SignalPlatformGraphic = RailGraphics->Plat68;
11000  SignalPlatformGraphic = RailGraphics->gl76;
11001  }
11002  Utilities->CallLogPop(950);
11003  return(true);
11004  }
11005  }
11006  else if(SpeedTag == 69) // bot sig
11007  {
11008  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11009  {
11010  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11011  {
11012  IAElement = InactiveTrackElementAt(77, IMPair.first);
11013  }
11014  else
11015  {
11016  IAElement = InactiveTrackElementAt(78, IMPair.second);
11017  }
11018  if(IAElement.LocationName == "")
11019  {
11020 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11021  SignalPlatformGraphic = RailGraphics->bm77Striped;
11022  }
11023  else
11024  {
11025 // SignalPlatformGraphic = RailGraphics->Plat69;
11026  SignalPlatformGraphic = RailGraphics->bm77;
11027  }
11028  Utilities->CallLogPop(951);
11029  return(true);
11030  }
11031  }
11032  else if(SpeedTag == 70) // left sig
11033  {
11034  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11035  {
11036  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11037  {
11038  IAElement = InactiveTrackElementAt(55, IMPair.first);
11039  }
11040  else
11041  {
11042  IAElement = InactiveTrackElementAt(82, IMPair.second);
11043  }
11044  if(IAElement.LocationName == "")
11045  {
11046 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11047  SignalPlatformGraphic = RailGraphics->bm78Striped;
11048  }
11049  else
11050  {
11051 // SignalPlatformGraphic = RailGraphics->Plat70;
11052  SignalPlatformGraphic = RailGraphics->bm78;
11053  }
11054  Utilities->CallLogPop(952);
11055  return(true);
11056  }
11057  }
11058  else if(SpeedTag == 71) // right sig
11059  {
11060  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11061  {
11062  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11063  {
11064  IAElement = InactiveTrackElementAt(85, IMPair.first);
11065  }
11066  else
11067  {
11068  IAElement = InactiveTrackElementAt(86, IMPair.second);
11069  }
11070  if(IAElement.LocationName == "")
11071  {
11072 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11073  SignalPlatformGraphic = RailGraphics->gl79Striped;
11074  }
11075  else
11076  {
11077 // SignalPlatformGraphic = RailGraphics->Plat71;
11078  SignalPlatformGraphic = RailGraphics->gl79;
11079  }
11080  Utilities->CallLogPop(953);
11081  return(true);
11082  }
11083  }
11084  Utilities->CallLogPop(954);
11085  return(false);
11086 }
11087 
11088 // ---------------------------------------------------------------------------
11089 
11090 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
11091 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
11092 // false if not, if NextPos == -1, or if only own train on the track
11093 {
11094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
11095  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
11096  if(NextEntryPos < 0)
11097  {
11098  Utilities->CallLogPop(1348);
11099  return(false);
11100  }
11101  TTrackElement TrackElement = TrackElementAt(713, NextPos);
11102 
11103  if(TrackElement.TrackType != Bridge)
11104  {
11105  Utilities->CallLogPop(1349);
11106  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11107  }
11108 // bridge if reach here
11109  if(NextEntryPos > 1)
11110  {
11111  Utilities->CallLogPop(1350);
11112  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11113  }
11114  else
11115  {
11116  Utilities->CallLogPop(1351);
11117  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11118  }
11119 }
11120 
11121 // ---------------------------------------------------------------------------
11122 
11124 {
11125  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11126  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11127  {
11128  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11129  }
11130  Utilities->CallLogPop(1483);
11131  return(SelectVector.at(At));
11132 }
11133 
11134 // ---------------------------------------------------------------------------
11135 
11136 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11137 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11138 {
11139  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11140  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11141  bool FoundFlag = false;
11142  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11143  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11144 
11145  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11146  Utilities->CallLogPop(1538);
11147  return(FoundFlag);
11148 }
11149 
11150 // ---------------------------------------------------------------------------
11151 
11152 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11153 {
11154 // return true if find an inactive element called 'Name'
11155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11156  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11157  bool FoundFlag = false;
11158 
11159  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11160  {
11161  if(InactiveTrackElementAt(158, x).LocationName == Name)
11162  {
11163  FoundFlag = true;
11164  int V = InactiveTrackElementAt(159, x).VLoc;
11165  int H = InactiveTrackElementAt(160, x).HLoc;
11166  if(V > VLocHi)
11167  {
11168  VLocHi = V;
11169  }
11170  if(V < VLocLo)
11171  {
11172  VLocLo = V;
11173  }
11174  if(H < HLoc)
11175  {
11176  HLoc = H;
11177  }
11178  }
11179  }
11180  if(FoundFlag)
11181  {
11182  VPosHi = 16 * VLocHi;
11183  VPosLo = 16 * VLocLo;
11184  HPos = 16 * HLoc;
11185  Utilities->CallLogPop(1562);
11186  return(true);
11187  }
11188  else
11189  {
11190  Utilities->CallLogPop(1563);
11191  return(false);
11192  }
11193 }
11194 
11195 // ---------------------------------------------------------------------------
11196 
11197 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11198 {
11199 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11200 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11202  AnsiString(EndTVPosition));
11203  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11204  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11205 
11206 // get H & V values for the element adjacent to Link[0] & Link[1]
11207  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11208  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11209  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11210  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11211 
11212 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11213  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11214  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11215  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11216  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11217 
11218  if(Link0Squares <= Link1Squares)
11219  {
11220  Utilities->CallLogPop(1851);
11221  return(0);
11222  }
11223  else
11224  {
11225  Utilities->CallLogPop(1852);
11226  return(1);
11227  }
11228 }
11229 
11230 // ---------------------------------------------------------------------------
11231 
11232 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11233 {
11234  // element can be points or any other type
11235  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11236  AnsiString(LinkPos));
11237  Derail = false;
11238  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11239 
11240  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11241  {
11242  if(TE.Attribute == 0)
11243  {
11244  Utilities->CallLogPop(663);
11245  return(1); // Att == 0 & ExitPos == 1 represent straight
11246  }
11247  else
11248  {
11249  Utilities->CallLogPop(664);
11250  return(3); // Att == 1 & ExitPos == 3 represent diverging
11251  }
11252  }
11253  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11254  {
11255  if((LinkPos == 1) && (TE.Attribute == 0))
11256  {
11257  Utilities->CallLogPop(665);
11258  return(0); // Att == 0 represents straight
11259  }
11260  else if(LinkPos == 1)
11261  {
11262  Derail = true;
11263  Utilities->CallLogPop(666);
11264  return(0);
11265  }
11266  else if((LinkPos == 3) && (TE.Attribute == 1))
11267  {
11268  Utilities->CallLogPop(667);
11269  return(0);
11270  }
11271  else if(LinkPos == 3)
11272  {
11273  Derail = true;
11274  Utilities->CallLogPop(668);
11275  return(0);
11276  }
11277  }
11278  else if(LinkPos == 0)
11279  {
11280  Utilities->CallLogPop(669);
11281  return(1);
11282  }
11283  else if(LinkPos == 1)
11284  {
11285  Utilities->CallLogPop(670);
11286  return(0);
11287  }
11288  else if(LinkPos == 2)
11289  {
11290  Utilities->CallLogPop(671);
11291  return(3);
11292  }
11293  else if(LinkPos == 3)
11294  {
11295  Utilities->CallLogPop(672);
11296  return(2);
11297  }
11298  throw Exception("Error, failure in GetExitPos"); // should never reach here
11299 }
11300 
11301 // ----------------------------------------------------------------------------
11302 
11304 {
11305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11306  LCVector.clear();
11307  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11308  {
11309  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11310  {
11311  LCVector.push_back(x);
11312  }
11313  }
11314  Utilities->CallLogPop(1931);
11315  return;
11316 }
11317 
11318 // ---------------------------------------------------------------------------
11319 
11320 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11321 /*
11322  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11323  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11324  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11325  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11326 */
11327 {
11328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11329  AnsiString(Link));
11330  bool FoundFlag;
11331 
11332  TrainID = -1;
11333  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11334 
11335  if(!FoundFlag)
11336  {
11337  Utilities->CallLogPop(2001);
11338  return(false);
11339  }
11340  TTrackElement TE = TrackElementAt(882, VecPos);
11341 
11342  TrainID = TE.TrainIDOnElement;
11343  if(TE.TrackType == Bridge)
11344  {
11345  if(TE.TrainIDOnElement > -1)
11346  {
11347  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11348  {
11350  }
11351  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11352  {
11354  }
11355  else
11356  {
11357  TrainID = -1; // shouldn't ever reach here but be safe
11358  }
11359  }
11360  }
11361  if(TrainID == -1)
11362  {
11363  Utilities->CallLogPop(2002);
11364  return(false);
11365  }
11366 // now get the train
11367  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11368 
11369  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11370  {
11371  Utilities->CallLogPop(2003);
11372  return(true);
11373  }
11374  TrainID = -1;
11375  Utilities->CallLogPop(2004);
11376  return(false);
11377 }
11378 
11379 // ---------------------------------------------------------------------------
11380 
11381 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11382 /* New at v1.2.0
11383  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11384  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11385  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11386  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11387  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11388  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11389  Each of these is examined in turn for each route element in the relevant position.
11390 */
11391 {
11392  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11393  "," + AnsiString(DiagonalLinkNumber));
11394  TrainID = -1;
11395  TPrefDirElement TempPrefDirElement;
11396  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11397 
11398  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11399  {
11400  Utilities->CallLogPop(2027);
11401  return(true);
11402  }
11403  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11404  {
11405  Utilities->CallLogPop(2028);
11406  return(true);
11407  }
11408  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11409  {
11410  Utilities->CallLogPop(2029);
11411  return(true);
11412  }
11413  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11414  {
11415  Utilities->CallLogPop(2030);
11416  return(true);
11417  }
11418  Utilities->CallLogPop(2031);
11419  return(false);
11420 }
11421 
11422 // ---------------------------------------------------------------------------
11423 
11424 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11425 {
11426  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11427  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11428  TUserGraphicItem UGI;
11429  AnsiString JustFileName = "";
11430 
11431  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11432  {
11433  UGI = UserGraphicVectorAt(17, x);
11434  int LastDelim = UGI.FileName.LastDelimiter('\\');
11435  if(LastDelim == 0) // can't find it so skip this item
11436  {
11437  continue;
11438  }
11439  else
11440  {
11441  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11442  }
11443  Utilities->SaveFileString(VecFile, JustFileName);
11444  Utilities->SaveFileInt(VecFile, UGI.HPos);
11445  Utilities->SaveFileInt(VecFile, UGI.VPos);
11446  }
11447  Utilities->CallLogPop(2178);
11448 }
11449 
11450 // ---------------------------------------------------------------------------
11451 
11452 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11453 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11454 {
11455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11456  int NumPlats = 0;
11457  TTrackElement TempElement;
11458  int TempInt;
11459 
11460  typedef std::list<int> TNamePosList;
11461  TNamePosList NamePosList;
11462  typedef TNamePosList::iterator TNPLIt;
11463  TNPLIt NPLIt;
11464  typedef std::list<int> TOnePlatList;
11465  TOnePlatList OnePlatList;
11466  typedef TOnePlatList::iterator TOPLIt;
11467  TOPLIt OPLIt;
11468 
11469  NamePosList.clear();
11470  OnePlatList.clear();
11471  for(unsigned int x = 0; x < TrackVector.size(); x++)
11472  {
11473  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11474  {
11475  NamePosList.push_back(x);
11476  }
11477  }
11478  //NamePosList complete
11479 
11480  if(!NamePosList.empty()) //first value for the loop examination
11481  {
11482  OnePlatList.push_back(NamePosList.back());
11483  NamePosList.pop_back(); //erase from NPV as done with it here
11484  }
11485  while(!OnePlatList.empty()) //loop to examine all linked elements
11486  {
11487  TempInt = OnePlatList.front();
11488  TempElement = TrackElementAt(989, TempInt);
11489 
11490  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11491  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11492  {
11493  OnePlatList.push_back(TempElement.Conn[0]);
11494  NamePosList.erase(NPLIt);
11495  }
11496  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11497  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11498  {
11499  OnePlatList.push_back(TempElement.Conn[1]);
11500  NamePosList.erase(NPLIt);
11501  }
11502  //here when loaded any connecting links into OnePlatList, so can erase the front element
11503  OnePlatList.erase(OnePlatList.begin());
11504  if(OnePlatList.empty())
11505  {
11506  NumPlats++; //finished with current linked elements so can increment NumPlats
11507  if(!NamePosList.empty())
11508  {
11509  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11510  NamePosList.pop_back(); //erase from NPV as done with it there
11511  }
11512  }
11513  }
11514  Utilities->CallLogPop(2218);
11515  return(NumPlats);
11516 }
11517 
11518 // ---------------------------------------------------------------------------
11519 
11520 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11521 {//repair Signals pointed to by FPVIt
11522  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
11523  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
11524  if(TE.TrackType != SignalPost)
11525  {
11526  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
11527  }
11528  if(!TE.Failed)
11529  {
11530  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
11531  }
11532  TE.Failed = false;
11533  //set to correct aspect
11534  int RouteNumber;
11535  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
11536  { // 0 for LinkPos ok as a signal so only one track
11537  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
11538  }
11539  //erase from vector
11540  Track->FailedSignalsVector.erase(FPVIt);
11541 
11542  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11543  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11544  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
11545  AllRoutes->RebuildRailwayFlag = true;
11546  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
11547  Utilities->CallLogPop(2519);
11548 }
11549 
11550 // ---------------------------------------------------------------------------
11551 
11552 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11553 {//repair points pointed to by FPVIt
11554  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
11555  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
11556  if(TE.TrackType != Points)
11557  {
11558  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
11559  }
11560  if(!TE.Failed)
11561  {
11562  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
11563  }
11564  TE.Failed = false;
11569  //erase from vector
11570  Track->FailedPointsVector.erase(FPVIt);
11571 
11572  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11573  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11574  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
11575  AllRoutes->RebuildRailwayFlag = true;
11576  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11577  Utilities->CallLogPop(2518);
11578 }
11579 
11580 // ---------------------------------------------------------------------------
11581 
11582 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11583 {//repair TSR pointed to by FPVIt
11584  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
11585  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
11586  if(TE.TrackType != Simple)
11587  {
11588  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
11589  }
11590  if(!TE.Failed)
11591  {
11592  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
11593  }
11594  TE.Failed = false;
11597  //erase from vector
11598  Track->TSRVector.erase(FPVIt);
11599 
11600  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11601  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11602  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
11603  AllRoutes->RebuildRailwayFlag = true;
11604  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11605  Utilities->CallLogPop(2520);
11606 }
11607 
11608 // ---------------------------------------------------------------------------
11609 
11611 {
11612  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
11613  SimpleVector.clear();
11614  for(unsigned int x = 0; x < TrackVector.size(); x++)
11615  {
11616  if(TrackElementAt(1517, x).TrackType == Simple)
11617  {
11618  SimpleVector.push_back(int(x));
11619  }
11620  }
11621  Utilities->CallLogPop(2521);
11622 }
11623 
11624 // ---------------------------------------------------------------------------
11625 // UserGraphic, PrefDir & Route functions
11626 // ---------------------------------------------------------------------------
11627 
11629 {
11630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11631  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11632  {
11633  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11634  }
11635  Utilities->CallLogPop(2194);
11636  return(UserGraphicVector.at(At));
11637 }
11638 
11639 // ---------------------------------------------------------------------------
11640 
11641 int TOnePrefDir::LastElementNumber(int Caller) const
11642 {
11643  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11644  int RetVal = PrefDirVector.size() - 1;
11645 
11646  if(RetVal < 0)
11647  {
11648  throw Exception("Return value negative in call to LastElementNumber");
11649  }
11650  Utilities->CallLogPop(114);
11651  return(RetVal);
11652 }
11653 
11654 // ---------------------------------------------------------------------------
11656 {
11657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11658  if(PrefDirVector.empty())
11659  {
11660  throw Exception("PrefDirVector empty in call to LastElementPtr");
11661  }
11662  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11663 
11664  Utilities->CallLogPop(115);
11665  return(RetIT);
11666 }
11667 
11668 // ---------------------------------------------------------------------------
11670 {
11671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11672  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11673  {
11674  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11675  }
11676  Utilities->CallLogPop(116);
11677  return(PrefDirVector.at(At));
11678 }
11679 
11680 // ---------------------------------------------------------------------------
11682 {
11683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11684  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11685  {
11686  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11687  " in GetModifiablePrefDirElementAt");
11688  }
11689  Utilities->CallLogPop(117);
11690  return(PrefDirVector.at(At));
11691 }
11692 
11693 // ---------------------------------------------------------------------------
11695 {
11696  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11697  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11698  {
11699  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11700  }
11701  Utilities->CallLogPop(118);
11702  return(SearchVector.at(At));
11703 }
11704 
11705 // ---------------------------------------------------------------------------
11707 {
11708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11709  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11710  {
11711  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11712  }
11713  Utilities->CallLogPop(119);
11714  return(SearchVector.at(At));
11715 }
11716 
11717 // ---------------------------------------------------------------------------
11718 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11719 /*
11720  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11721  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11722  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11723  set in later functions.
11724 */
11725 {
11726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11727  ClearPrefDir();
11728  int TrackVectorPosition;
11729  TTrackElement TrackElement;
11730 
11731  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11732  {
11733  Utilities->CallLogPop(126);
11734  return(false);
11735  }
11736 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11737  if(TrackElement.TrackType == Points)
11738  {
11739  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11740  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11741  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11742  //best to prevent it to avoid problems
11743  Utilities->CallLogPop(127);
11744  return false;
11745  }
11746 */
11747  TPrefDirElement PrefDirElement(TrackElement);
11748 
11749  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11750  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11751  StorePrefDirElement(1, PrefDirElement); // enter first element
11752 // Note that ELink not set even if a buffer or continuation - these set in
11753 // ConvertPrefDirSearchVector after 2nd element added
11754 
11755  Utilities->CallLogPop(128);
11756  return(true);
11757 }
11758 
11759 // ---------------------------------------------------------------------------
11760 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11761 
11762 /*
11763  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11764  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
11765  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11766  with setting the PrefDir vector, & return true.
11767  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11768  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
11769  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11770  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11771  ConvertPrefDirSearchVector to set PrefDirVector.
11772  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11773  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11774  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11775 */
11776 
11777 {
11778  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11779  FinishElement = false;
11780  int TrackVectorPosition;
11781 
11782  TotalSearchCount = 0;
11783  TTrackElement TrackElement, TempTrackElement;
11784 
11785  if(PrefDirVector.size() == 0)
11786  {
11787  Utilities->CallLogPop(129);
11788  return(false);
11789  }
11790  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11791  {
11792  Utilities->CallLogPop(130);
11793  return(false);
11794  }
11795 // set the search limits using the last stored element in PrefDirVector as the start point
11796 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11797 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11798 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11799 
11800  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11801 
11802  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11803  {
11804  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11805  SearchLimitHighH = TrackElement.HLoc + 15;
11806  }
11807  else
11808  {
11809  SearchLimitLowH = TrackElement.HLoc - 15;
11810  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11811  }
11812  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11813  {
11814  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11815  SearchLimitHighV = TrackElement.VLoc + 15;
11816  }
11817  else
11818  {
11819  SearchLimitLowV = TrackElement.VLoc - 15;
11820  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11821  }
11822 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11823  check & TotalSearchCounts check
11824  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11825  {
11826  ShowMessage("Unable to reach the selected element - too far ahead");
11827  Utilities->CallLogPop(1692);
11828  return false;
11829  }
11830 */
11831 // get last PrefDir element
11832  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11833  {
11834  // check if TrackElement adjacent to any of the 4 XLinkPos'
11835  for(int x = 0; x < 4; x++)
11836  {
11837  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11838  {
11839  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11840  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11841  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11842  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11843  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11844  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11845  // shouldn't ever get it in a serious railway though.
11846 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11847  }
11848  }
11849  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11850  {
11851  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11852  SearchVector.clear(); // use this & convert to set all PrefDir element values
11853  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11854  {
11856  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11857  {
11858  FinishElement = true;
11859  }
11860  Utilities->CallLogPop(131);
11861  return(true);
11862  }
11863  } // not an adjacent element
11864 
11865  // now check each of the 4 possible XLinkPos values
11866  for(int x = 0; x < 4; x++)
11867  {
11868  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11869  {
11870  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11871  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11872  SearchVector.clear();
11873  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11874  {
11876  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11877  {
11878  FinishElement = true;
11879  }
11880  Utilities->CallLogPop(132);
11881  return(true);
11882  }
11883  }
11884  } // here if checked all possible exits without success
11885  ShowMessage(
11886  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11887  Utilities->CallLogPop(133);
11888  return(false);
11889  }
11890 // dealt above with LastPrefDirElement being the start element (which can be points)
11891 
11892  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11893  .ELinkPos] == Lead)) // leading point
11894  {
11895  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11896  {
11897  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11898  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11899  // can't be buffers or gap if points
11900  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11901  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11902  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11903  SearchVector.clear();
11904  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11905  {
11907  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11908  {
11909  FinishElement = true;
11910  }
11911  Utilities->CallLogPop(134);
11912  return(true);
11913  }
11914  }
11915  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11916  {
11917  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11918  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11919  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11920  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11921  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11922  SearchVector.clear();
11923  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11924  {
11926  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11927  {
11928  FinishElement = true;
11929  }
11930  Utilities->CallLogPop(135);
11931  return(true);
11932  }
11933  }
11934 // above dealt with immediate finds for leading point,
11935 // now deal with ordinary searches for leading point
11936  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11937  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11938  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11939  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11940  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11941  SearchVector.clear();
11942  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11943  {
11945  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11946  {
11947  FinishElement = true;
11948  }
11949  Utilities->CallLogPop(136);
11950  return(true);
11951  }
11952  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11953  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11954  // note that CheckCount already increased to allow for XLinkPos & XLink
11955  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11956  SearchVector.clear();
11957  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11958  {
11960  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11961  {
11962  FinishElement = true;
11963  }
11964  Utilities->CallLogPop(137);
11965  return(true);
11966  }
11967 // here if failed to find match for leading point
11968  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11969  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11970  ShowMessage(
11971  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11972  Utilities->CallLogPop(138);
11973  return(false);
11974  }
11975 // leading point fully dealt with above
11976 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11977 // separately as covered in ordinary search.
11978 
11979  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11980  SearchVector.clear();
11981 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11982  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11983  {
11985  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11986  {
11987  FinishElement = true;
11988  }
11989  Utilities->CallLogPop(139);
11990  return(true);
11991  }
11992  ShowMessage(
11993  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11994  Utilities->CallLogPop(140);
11995  return(false); // failed to find required element
11996 }
11997 
11998 // ---------------------------------------------------------------------------
11999 
12000 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12001 /*
12002  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12003  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12004  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12005  Keep a count of entries in SearchVector during the current function call, so that this number can be
12006  erased for an unproductive branch search.
12007  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12008  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12009  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12010  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12011  If not any of above, store element in searchvector, set the new current element values from the
12012  SearchElement, then go back to the while loop for the next step in the search.
12013 */
12014 {
12015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12016  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12017  int VectorCount = 0;
12018 
12019  while(true)
12020  {
12021  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12022  {
12023  for(int x = 0; x < VectorCount; x++)
12024  {
12025  SearchVector.erase(SearchVector.end() - 1);
12026  }
12027  Utilities->CallLogPop(141);
12028  return(false);
12029  }
12030  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12031  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12032  TPrefDirElement SearchElement(NextTrackElement);
12033  SearchElement.TrackVectorPosition = NextPosition;
12034  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12035  SearchElement.ELinkPos = NextELinkPos;
12036  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12037  int NextXLinkPos;
12038  if(SearchElement.ELinkPos == 0)
12039  {
12040  NextXLinkPos = 1;
12041  }
12042  if(SearchElement.ELinkPos == 1)
12043  {
12044  NextXLinkPos = 0;
12045  }
12046  if(SearchElement.ELinkPos == 2)
12047  {
12048  NextXLinkPos = 3;
12049  }
12050  if(SearchElement.ELinkPos == 3)
12051  {
12052  NextXLinkPos = 2;
12053  }
12054  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12055  {
12056  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12057  // but may be buffers, continuation or gap
12058  SearchElement.XLinkPos = NextXLinkPos;
12059  }
12060 // can't set XLink or XLinkPos yet if the element is a leading point.
12061 // check if found it
12062  if(SearchElement.TrackVectorPosition == RequiredPosition)
12063  {
12064  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12065  VectorCount++; // not really needed but include for tidyness
12066  TotalSearchCount++;
12067  Utilities->CallLogPop(142);
12068  return(true);
12069  }
12070 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12071 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12072 // at a time - drop this
12073 /*
12074  if(PrefDirVector.size() > 200)
12075  {
12076  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12077  Utilities->CallLogPop(1419);
12078  return false;
12079  }
12080 */
12081 // check if a buffer or continuation
12082  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12083  {
12084  for(int x = 0; x < VectorCount; x++)
12085  {
12086  SearchVector.erase(SearchVector.end() - 1);
12087  }
12088  Utilities->CallLogPop(143);
12089  return(false);
12090  }
12091 // check if reached an earlier position on search PrefDir with same entry value
12092  for(unsigned int x = 0; x < SearchVector.size(); x++)
12093  {
12094  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12095  {
12096  for(int x = 0; x < VectorCount; x++)
12097  {
12098  SearchVector.erase(SearchVector.end() - 1);
12099  }
12100  Utilities->CallLogPop(144);
12101  return(false);
12102  }
12103  }
12104 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12105 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12106  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12107  {
12108  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12109  {
12110  for(int x = 0; x < VectorCount; x++)
12111  {
12112  SearchVector.erase(SearchVector.end() - 1);
12113  }
12114  Utilities->CallLogPop(1417);
12115  return(false);
12116  }
12117  }
12118 
12119 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12120 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12121 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12123  {
12124  for(int x = 0; x < VectorCount; x++)
12125  {
12126  SearchVector.erase(SearchVector.end() - 1);
12127  }
12128  Utilities->CallLogPop(1691);
12129  return(false);
12130  }
12131 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12132  if(SearchVector.size() > 150)
12133  {
12134  for(int x = 0; x < VectorCount; x++)
12135  {
12136  SearchVector.erase(SearchVector.end() - 1);
12137  }
12138  Utilities->CallLogPop(1418);
12139  return(false);
12140  }
12141 // check if reached a leading point
12142  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12143  {
12144 // push element with XLink set to position [1]
12145  SearchElement.XLink = SearchElement.Link[1];
12146  SearchElement.XLinkPos = 1;
12147  SearchVector.push_back(SearchElement);
12148  VectorCount++;
12149  TotalSearchCount++;
12150  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12151  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12152  // can't be used. NextTrackElement is the corresponding TTrackElement.
12153  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12154  {
12155  Utilities->CallLogPop(145);
12156  return(true);
12157  }
12158  else
12159  {
12160 // remove leading point with XLinkPos [1]
12161  SearchVector.erase(SearchVector.end() - 1);
12162  VectorCount--;
12163 // push element with XLink set to position [3]
12164  SearchElement.XLink = SearchElement.Link[3];
12165  SearchElement.XLinkPos = 3;
12166  SearchVector.push_back(SearchElement);
12167  VectorCount++;
12168  TotalSearchCount++;
12169 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12170  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12171  {
12172  Utilities->CallLogPop(146);
12173  return(true);
12174  }
12175  else
12176  {
12177  for(int x = 0; x < VectorCount; x++)
12178  {
12179  SearchVector.erase(SearchVector.end() - 1);
12180  }
12181  Utilities->CallLogPop(147);
12182  return(false);
12183  }
12184  }
12185  } // if leading point
12186 
12187 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12188 // ready for next element on PrefDir
12189  SearchVector.push_back(SearchElement);
12190  VectorCount++;
12191  TotalSearchCount++;
12192  XLinkPos = NextXLinkPos;
12193  CurrentTrackElement = SearchElement;
12194  } // while(true)
12195 }
12196 
12197 // ---------------------------------------------------------------------------
12198 
12200 /*
12201  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12202  for each element on the search PrefDir, though if the last element is a leading point
12203  then the final XLink won't be set.
12204  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12205  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12206  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12207 */
12208 {
12209  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12210  if(SearchVector.size() == 0)
12211  {
12212  throw Exception("Error, SearchVector empty");
12213  }
12214 // get first SearchElement in order to set last PrefDirelement
12215  TPrefDirElement SearchElement = SearchVector.at(0);
12216 
12217 // set last PrefDir element XLink & ELink values if not already set
12218 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12219  for(int x = 0; x < 4; x++)
12220  {
12221  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12222  {
12223  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12224  {
12225  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12226  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12227  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12228  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12229  }
12230  int ELinkPos;
12231  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12232  {
12233  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12234  }
12235  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12236  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12237  {
12238  ELinkPos = 0;
12239  }
12240  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12241  {
12242  ELinkPos = 3;
12243  }
12244  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12245  {
12246  ELinkPos = 2;
12247  }
12248  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12249  {
12250  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12251  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12252  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12253  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12254  }
12255  break; // no point going any further
12256  }
12257  }
12258 // set EXNumber for last PrefDir element, unless already set
12259 // won't be set if was first element or a leading point
12260  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12261  {
12262 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12263  int EXArray[32][2] = {
12264  {4,6},{2,8}, //horizontal & vertical
12265  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12266  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12267  {1,9},{3,7} //forward & reverse diagonals
12268 */
12269 
12270  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12271  {
12272  throw Exception("Error in EntryExitNumber 1");
12273  }
12274  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12275  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12276  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12277  }
12278 // Last PrefDir element now complete
12279 
12280 // construct remaining PrefDir elements from searchvector
12281  for(unsigned int x = 0; x < SearchVector.size(); x++)
12282  {
12283  SearchElement = SearchVector.at(x);
12284  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12285  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12286  PrefDirElement.ELink = SearchElement.ELink;
12287  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12288  PrefDirElement.XLink = SearchElement.XLink;
12289  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12290 // if XLink & XLinkPos not set don't account for them in CheckCount
12291  if(PrefDirElement.XLink == -1)
12292  {
12293  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12294  }
12295  // & TrackVectorPosition
12296  else
12297  {
12298  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12299  }
12300  // XLink, XLinkPos, TrackVectorPosition
12301 
12302 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12303  if(PrefDirElement.XLink != -1)
12304  {
12305  if(!(PrefDirElement.EntryExitNumber()))
12306  {
12307  throw Exception("Error in EntryExitNumber 2");
12308  }
12309  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12310  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12311  PrefDirElement.CheckCount++;
12312  // all values now incorporated if not a leading point
12313  }
12314 // store PrefDir element
12315  StorePrefDirElement(2, PrefDirElement);
12316  }
12317 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12318  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12319  {
12320  if(ValidatePrefDir(2))
12321  {
12322  ;
12323  } // error messages given within function
12324 
12325  }
12327 /* drop this, check dropped from search
12328  if(PrefDirVector.size() > 200)
12329  {
12330  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12331  }
12332 */
12333  Utilities->CallLogPop(148);
12334 }
12335 
12336 // ---------------------------------------------------------------------------
12337 
12338 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12339 /*
12340  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12341  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12342 */
12343 {
12344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12345  LeadingPoints = false;
12346  if(PrefDirVector.empty())
12347  {
12348  Utilities->CallLogPop(1786);
12349  return(false); // should never be empty but allow for it for safety
12350  }
12351  if(PrefDirVector.size() == 1)
12352  {
12353  Utilities->CallLogPop(149);
12354  return(false); // can't end if only one element
12355  }
12356 /*
12357  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12358  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12359  {
12360  Utilities->CallLogPop(150);
12361  return true;
12362  }
12363 */
12364 // allow for anything but leading points
12365  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12366  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12367  {
12368  Utilities->CallLogPop(1776);
12369  return(true);
12370  }
12371  else
12372  {
12373  LeadingPoints = true;
12374  Utilities->CallLogPop(151);
12375  return(false);
12376  }
12377 }
12378 
12379 // ---------------------------------------------------------------------------
12380 
12382 /*
12383  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12384  and that every element is connected to the next element
12385 */
12386 {
12387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12388  int Position;
12389  AnsiString ErrorString;
12390  bool Error = false;
12391 
12392  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12393  {
12394  if(PrefDirVector.at(x).HLoc == -2000000000)
12395  {
12396  Error = true;
12397  ErrorString = "HLoc";
12398  Position = x;
12399  }
12400  if(PrefDirVector.at(x).VLoc == -2000000000)
12401  {
12402  Error = true;
12403  ErrorString = "VLoc";
12404  Position = x;
12405  }
12406  if(PrefDirVector.at(x).ELink == -1)
12407  {
12408  Error = true;
12409  ErrorString = "ELink";
12410  Position = x;
12411  }
12412  if(PrefDirVector.at(x).ELinkPos == -1)
12413  {
12414  Error = true;
12415  ErrorString = "ELinkPos";
12416  Position = x;
12417  }
12418  if(PrefDirVector.at(x).XLink == -1)
12419  {
12420  Error = true;
12421  ErrorString = "XLink";
12422  Position = x;
12423  }
12424  if(PrefDirVector.at(x).XLinkPos == -1)
12425  {
12426  Error = true;
12427  ErrorString = "XLinkPos";
12428  Position = x;
12429  }
12430  if(PrefDirVector.at(x).SpeedTag == 0)
12431  {
12432  Error = true;
12433  ErrorString = "Tag";
12434  Position = x;
12435  }
12436  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12437  {
12438  Error = true;
12439  ErrorString = "TrackVectorPosition";
12440  Position = x;
12441  }
12442  if(PrefDirVector.at(x).EXNumber == -1)
12443  {
12444  Error = true;
12445  ErrorString = "EXNumber";
12446  Position = x;
12447  }
12448  if(PrefDirVector.at(x).CheckCount != 9)
12449  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12450  {
12451  Error = true;
12452  ErrorString = "CheckCount";
12453  Position = x;
12454  }
12455 // extra checks
12456  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12457  {
12458  Error = true;
12459  ErrorString = "EntryGraphicPtr";
12460  Position = x;
12461  }
12462  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12463  {
12464  Error = true;
12465  ErrorString = "EntryDirectionGraphicPtr";
12466  Position = x;
12467  }
12468 // end of extra checks
12469  if(x > 0)
12470  {
12471  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12472  {
12473  Error = true;
12474  ErrorString = "Last XLink not connected to this element";
12475  Position = x;
12476  }
12477  }
12478  }
12479  if(Error)
12480  {
12481  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12482  }
12483  else
12484  {
12485  Utilities->CallLogPop(153);
12486  return(true);
12487  }
12488 }
12489 
12490 // ---------------------------------------------------------------------------
12491 
12492 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12493 /*
12494  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12495  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12496  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12497  or a leading point.
12498 */
12499 {
12500  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12501  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12502  {
12503  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12504  {
12505  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12506  {
12507  ErasePrefDirElementAt(1, PrefDirVecPos);
12508  }
12509  if(PrefDirVector.size() == 0)
12510  {
12511  Utilities->CallLogPop(154);
12512  return(true);
12513  }
12514  if(PrefDirVector.size() == 1)
12515  {
12516  PrefDirVector.at(x - 1).ELinkPos = -1;
12517  PrefDirVector.at(x - 1).ELink = -1;
12518  PrefDirVector.at(x - 1).XLinkPos = -1;
12519  PrefDirVector.at(x - 1).XLink = -1;
12520  PrefDirVector.at(x - 1).EXNumber = -1;
12521  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12522  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12523  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12524  Utilities->CallLogPop(155);
12525  return(true);
12526  }
12527  // here with truncate element not first element, so ELink & ELinkPos set
12528  // unset XLink & Pos if a leading point
12529  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12530  {
12531  PrefDirVector.at(x - 1).XLinkPos = -1;
12532  PrefDirVector.at(x - 1).XLink = -1;
12533  PrefDirVector.at(x - 1).EXNumber = -1;
12534  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12535  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12536  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12537  Utilities->CallLogPop(156);
12538  return(true);
12539  }
12540  Utilities->CallLogPop(157);
12541  return(true);
12542  }
12543  }
12544  Utilities->CallLogPop(158);
12545  return(false);
12546 }
12547 
12548 // ---------------------------------------------------------------------------
12549 
12550 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12551 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12552 /*
12553  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12554  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12555  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12556  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12557  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12558  displayed.
12559 */
12560 {
12561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12562  AnsiString((short)BuildingPrefDir));
12563  int HPos, VPos;
12564 
12565  if(PrefDirSize() == 0)
12566  {
12567  Utilities->CallLogPop(159);
12568  return;
12569  }
12570  for(unsigned int x = 0; x < PrefDirSize(); x++)
12571  {
12572  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12573 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12574 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12575 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12576  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12577  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12578  // only the front half of which will be overplotted by the back of the train, then when the train is
12579  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12580  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12581  {
12582  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12583  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12584  {
12585  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12586  }
12587  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12588  // Route, no direction if a single element
12589  {
12590  if(x == 0)
12591  {
12592  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12593  }
12594  if(x == (PrefDirSize() - 1))
12595  {
12596  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12597  }
12598  }
12599  }
12600  }
12601 
12602 // set start & end element colours if building a PrefDir
12603  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12604  {
12605  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12606  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12607  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12608  // set last element colour
12609  if(PrefDirSize() > 1)
12610  {
12611  unsigned int LatestPos = PrefDirSize() - 1;
12612  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12613  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12614  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12615  }
12616  }
12617  Disp->Update();
12618  Utilities->CallLogPop(160);
12619 }
12620 
12621 // ---------------------------------------------------------------------------
12622 
12624 /*
12625  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12626  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12627 */
12628 {
12629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12630  if(PrefDirSize() == 0)
12631  {
12632  Utilities->CallLogPop(1547);
12633  return;
12634  }
12635  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12636  bool FoundFlag;
12638  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12639 
12640  while(MMIT != PrefDir4MultiMap.end())
12641  {
12642  H = MMIT->first.first;
12643  V = MMIT->first.second;
12644  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12645  // always found in order, any missing have PrefDirPosx == -1
12646  if(PrefDirPos0 > -1)
12647  {
12648  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12649  }
12650  if(PrefDirPos1 > -1)
12651  {
12652  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12653  }
12654  if(PrefDirPos2 > -1)
12655  {
12656  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12657  }
12658  if(PrefDirPos3 > -1)
12659  {
12660  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12661  }
12662  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12663  {
12664  // need to plot all 4 in order to obtain all the direction graphics
12665  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12666  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12667  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12668  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12669  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12670  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12671  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12672  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12673  MMIT++;
12674  MMIT++;
12675  MMIT++;
12676  MMIT++;
12677  }
12678  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12679  {
12680  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12681  {
12682  // 0 & 1 constitute the bidirectional PrefDir
12683  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12684  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12685  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12686  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12687  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12688  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12689  MMIT++;
12690  MMIT++;
12691  MMIT++;
12692  }
12693  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12694  {
12695  // 0 & 2 constitute the bidirectional PrefDir
12696  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12697  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12698  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12699  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12700  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12701  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12702  MMIT++;
12703  MMIT++;
12704  MMIT++;
12705  }
12706  else
12707  {
12708  // 1 & 2 constitute the bidirectional PrefDir
12709  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12710  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12711  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12712  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12713  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12714  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12715  MMIT++;
12716  MMIT++;
12717  MMIT++;
12718  }
12719  }
12720  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12721  {
12722  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12723  {
12724  // 0 & 1 constitute the bidirectional PrefDir
12725  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12726  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12727  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12728  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12729  MMIT++;
12730  MMIT++;
12731  }
12732  else
12733  {
12734  // 2 unidirectional PrefDirs
12735  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12736  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12737  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12738  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12739  MMIT++;
12740  MMIT++;
12741  }
12742  }
12743  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12744  {
12745  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12746  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12747  MMIT++;
12748  }
12749  }
12750  Disp->Update();
12751  Utilities->CallLogPop(1548);
12752 }
12753 
12754 // ---------------------------------------------------------------------------
12755 
12756 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12757 {
12758  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12759  int TempInt;
12760 
12761  ClearPrefDir();
12762  int NumberOfPrefDirElements = 0;
12763 
12764  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12765  for(int x = 0; x < NumberOfPrefDirElements; x++)
12766  {
12767  VecFile >> TempInt; // TrackVectorPosition
12768  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12769  LoadPrefDirElement.TrackVectorPosition = TempInt;
12770  VecFile >> TempInt;
12771  LoadPrefDirElement.ELink = TempInt;
12772  VecFile >> TempInt;
12773  LoadPrefDirElement.ELinkPos = TempInt;
12774  VecFile >> TempInt;
12775  LoadPrefDirElement.XLink = TempInt;
12776  VecFile >> TempInt;
12777  LoadPrefDirElement.XLinkPos = TempInt;
12778  VecFile >> TempInt;
12779  LoadPrefDirElement.EXNumber = TempInt;
12780  VecFile >> TempInt;
12781  LoadPrefDirElement.CheckCount = TempInt;
12782  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12783  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12784  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12785  if(!(LoadPrefDirElement.IsARoute))
12786  {
12787  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12788  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12789  }
12790  else
12791  {
12792  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12793  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12794  LoadPrefDirElement.PrefDirRoute);
12795  }
12796  StorePrefDirElement(5, LoadPrefDirElement);
12797  Utilities->LoadFileString(VecFile); // marker
12798  }
12800  Utilities->CallLogPop(161);
12801 }
12802 
12803 // ---------------------------------------------------------------------------
12804 
12805 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12806 {
12807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12808  int TempInt;
12809 
12810  ClearPrefDir();
12811  int NumberOfPrefDirElements = 0;
12812 
12813  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12814  for(int x = 0; x < NumberOfPrefDirElements; x++)
12815  {
12816  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12817  VecFile >> TempInt; // TrackVectorPosition
12818  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12819  LoadPrefDirElement.TrackVectorPosition = TempInt;
12820  VecFile >> TempInt;
12821  LoadPrefDirElement.ELink = TempInt;
12822  VecFile >> TempInt;
12823  LoadPrefDirElement.ELinkPos = TempInt;
12824  VecFile >> TempInt;
12825  LoadPrefDirElement.XLink = TempInt;
12826  VecFile >> TempInt;
12827  LoadPrefDirElement.XLinkPos = TempInt;
12828  VecFile >> TempInt;
12829  LoadPrefDirElement.EXNumber = TempInt;
12830  VecFile >> TempInt;
12831  LoadPrefDirElement.CheckCount = TempInt;
12832  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12833  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12834  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12835  if(!(LoadPrefDirElement.IsARoute))
12836  {
12837  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12838  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12839  }
12840  else
12841  {
12842  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12843  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12844  LoadPrefDirElement.PrefDirRoute);
12845  }
12846  StorePrefDirElement(0, LoadPrefDirElement);
12847  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12848  }
12850  Utilities->CallLogPop(1509);
12851 }
12852 
12853 // ---------------------------------------------------------------------------
12854 
12855 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12856 /*
12857  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12858  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12859 */
12860 {
12861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12862  int TempInt;
12863  int NumberOfPrefDirElements = 0;
12864 
12865  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12866  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12867  {
12868  Utilities->CallLogPop(1152);
12869  return(false);
12870  }
12871  for(int x = 0; x < NumberOfPrefDirElements; x++)
12872  {
12873  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12874  {
12875  Utilities->CallLogPop(1766);
12876  return(false);
12877  }
12878  VecFile >> TempInt;
12879  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12880  {
12881  Utilities->CallLogPop(163);
12882  return(false);
12883  }
12884  VecFile >> TempInt;
12885  if((TempInt < -1) || (TempInt > 9)) // ELink
12886  {
12887  Utilities->CallLogPop(162);
12888  return(false);
12889  }
12890  VecFile >> TempInt;
12891  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12892  {
12893  Utilities->CallLogPop(164);
12894  return(false);
12895  }
12896  VecFile >> TempInt;
12897  if((TempInt < -1) || (TempInt > 9)) // XLink
12898  {
12899  Utilities->CallLogPop(165);
12900  return(false);
12901  }
12902  VecFile >> TempInt;
12903  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12904  {
12905  Utilities->CallLogPop(166);
12906  return(false);
12907  }
12908  VecFile >> TempInt;
12909  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12910  {
12911  Utilities->CallLogPop(167);
12912  return(false);
12913  }
12914  VecFile >> TempInt;
12915  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12916  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12917  // ELinkPos, XLink, XLinkPos & EXNumber
12918  {
12919  Utilities->CallLogPop(168);
12920  return(false);
12921  }
12922  VecFile >> TempInt;
12923  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12924  {
12925  Utilities->CallLogPop(1147);
12926  return(false);
12927  }
12928  VecFile >> TempInt;
12929  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12930  {
12931  Utilities->CallLogPop(1510);
12932  return(false);
12933  }
12934  VecFile >> TempInt;
12935  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12936  {
12937  Utilities->CallLogPop(1148);
12938  return(false);
12939  }
12940  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12941  {
12942  Utilities->CallLogPop(1700);
12943  return(false);
12944  }
12945  }
12946  Utilities->CallLogPop(169);
12947  return(true);
12948 }
12949 
12950 // ---------------------------------------------------------------------------
12951 
12952 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12953 {
12954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12955  int NumberOfPrefDirElements = PrefDirVector.size();
12956 
12957  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12958  for(int y = 0; y < NumberOfPrefDirElements; y++)
12959  {
12960  VecFile << y << '\n'; // extra
12961  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12962  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12963  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12964  VecFile << PrefDirVector.at(y).XLink << '\n';
12965  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12966  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12967  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12968  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12969  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12970  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12971  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12972  {
12973  VecFile << "************" << '\0' << '\n'; // marker
12974  }
12975  else
12976  {
12977  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12978  }
12979  }
12980  Utilities->CallLogPop(170);
12981 }
12982 
12983 // ---------------------------------------------------------------------------
12984 
12985 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12986 {
12987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12988  int NumberOfSearchElements = SearchVector.size();
12989 
12990  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12991  for(int y = 0; y < NumberOfSearchElements; y++)
12992  {
12993  VecFile << y << '\n'; // extra
12994  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12995  VecFile << SearchVector.at(y).ELink << '\n';
12996  VecFile << SearchVector.at(y).ELinkPos << '\n';
12997  VecFile << SearchVector.at(y).XLink << '\n';
12998  VecFile << SearchVector.at(y).XLinkPos << '\n';
12999  VecFile << SearchVector.at(y).EXNumber << '\n';
13000  VecFile << SearchVector.at(y).CheckCount << '\n';
13001  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13002  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13003  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13004  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13005  {
13006  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13007  }
13008  else
13009  {
13010  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13011  }
13012  }
13013  Utilities->CallLogPop(1847);
13014 }
13015 
13016 // ---------------------------------------------------------------------------
13017 
13018 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13019 /*
13020  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13021  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13022 */
13023 {
13024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13025  AnsiString(VLoc));
13026  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13027 
13028  if(VecPos > -1)
13029  {
13030  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13031  }
13032  else
13033  {
13034  Utilities->CallLogPop(171);
13035  return;
13036  }
13037  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13038  if(VecPos > -1)
13039  {
13040  ErasePrefDirElementAt(3, VecPos);
13041  }
13042  else
13043  {
13044  Utilities->CallLogPop(172);
13045  return;
13046  }
13047  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13048  if(VecPos > -1)
13049  {
13050  ErasePrefDirElementAt(4, VecPos);
13051  }
13052  else
13053  {
13054  Utilities->CallLogPop(173);
13055  return;
13056  }
13057  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13058  if(VecPos > -1)
13059  {
13060  ErasePrefDirElementAt(5, VecPos);
13061  }
13062  else
13063  {
13064  Utilities->CallLogPop(174);
13065  return;
13066  }
13067  Utilities->CallLogPop(175);
13068 }
13069 
13070 // ---------------------------------------------------------------------------
13071 /*
13072  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13073  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13074 
13075  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13076  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13077  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13078  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13079  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13080  PrefDirVector to correspond to the new track layout.
13081 
13082  {
13083  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13084  if(PrefDirSize() == 0)
13085  {
13086  Utilities->CallLogPop(176);
13087  return;
13088  }
13089  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13090  {
13091  int TV = PrefDirVector.at(x).TrackVectorPosition;
13092  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13093  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13094  if(Track->BlankElementAt(0, TV))
13095  {
13096  ErasePrefDirElementAt(6, x);
13097  }
13098  //if was a blankelement at x then ConnELink and ConnXLink both -1
13099  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13100  {
13101  ErasePrefDirElementAt(7, x);
13102  }
13103  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13104  //needs to be erased once, but if don't use 'else' then will erase two elements
13105  //since 'x' will correspond to the element after the first erased element
13106  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13107  {
13108  ErasePrefDirElementAt(8, x);
13109  }
13110  }
13111  Utilities->CallLogPop(177);
13112  }
13113 */
13114 // ---------------------------------------------------------------------------
13115 
13116 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13117 /*
13118  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13119  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13120 */
13121 {
13122  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13123  bool AlreadyPresent, FoundFlag;
13124  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13125 
13126  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13127  {
13128  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13129  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13130  AlreadyPresent = false;
13131  if(FoundFlag)
13132  {
13133  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13134  {
13135  AlreadyPresent = true;
13136  }
13137  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13138  {
13139  AlreadyPresent = true;
13140  }
13141  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13142  {
13143  AlreadyPresent = true;
13144  }
13145  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13146  {
13147  AlreadyPresent = true;
13148  }
13149  }
13150  if(!AlreadyPresent)
13151  {
13152  StorePrefDirElement(4, TempElement);
13153  }
13154  }
13156  Utilities->CallLogPop(178);
13157 }
13158 /* earlier brute force search
13159  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13160  {
13161  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13162  bool AlreadyPresent = false;
13163  for(unsigned int y = 0;y<PrefDirSize();y++)
13164  {
13165  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13166  }
13167  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13168  }
13169 */
13170 
13171 // ---------------------------------------------------------------------------
13172 
13174 /*
13175  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13176  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13177  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13178  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13179  positions are likely to have changed, so this function is called to reset all the necessary connections and
13180  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13181  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13182  shouldn't have changed.
13183 */
13184 {
13185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13186  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13187  {
13188  bool FoundFlag;
13189  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13190  if(FoundFlag)
13191  {
13192  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13193  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13194  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13195  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13196  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13197  for(unsigned int z = 0; z < 4; z++)
13198  {
13199  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13200  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13201  }
13202  }
13203  else
13204  {
13205  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13206  }
13207  }
13208  Utilities->CallLogPop(179);
13209 }
13210 
13211 // ---------------------------------------------------------------------------
13212 
13214 /*
13215  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13216 */
13217 {
13218  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13219  bool DiscrepancyFound = false;
13220 
13221  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13222  {
13223  bool FoundFlag;
13224  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13225  if(FoundFlag)
13226  {
13227  TPrefDirElement PE = PrefDirVector.at(x);
13228  if(PE.TrackVectorPosition != VecPos)
13229  {
13230  DiscrepancyFound = true;
13231  break;
13232  }
13233  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13234  {
13235  DiscrepancyFound = true;
13236  break;
13237  }
13238  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13239  {
13240  DiscrepancyFound = true;
13241  break;
13242  }
13243  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13244  {
13245  DiscrepancyFound = true;
13246  break;
13247  }
13248  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13249  {
13250  DiscrepancyFound = true;
13251  break;
13252  }
13253  }
13254  else
13255  {
13256  DiscrepancyFound = true;
13257  }
13258  }
13259  if(DiscrepancyFound)
13260  {
13261  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13262  ClearPrefDir(); // also clears multimap
13263  }
13264  Utilities->CallLogPop(1436);
13265 }
13266 
13267 // ---------------------------------------------------------------------------
13268 
13270 /*
13271  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13272  return true for OK
13273 */
13274 {
13275  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13276  bool DiscrepancyFound = false;
13277 
13278  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13279  {
13280  bool FoundFlag;
13281  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13282  if(FoundFlag)
13283  {
13284  TPrefDirElement PE = PrefDirVector.at(x);
13285  if(PE.TrackVectorPosition != VecPos)
13286  {
13287  DiscrepancyFound = true;
13288  }
13289  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13290  {
13291  DiscrepancyFound = true;
13292  break;
13293  }
13294  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13295  {
13296  DiscrepancyFound = true;
13297  break;
13298  }
13299  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13300  {
13301  DiscrepancyFound = true;
13302  break;
13303  }
13304  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13305  {
13306  DiscrepancyFound = true;
13307  break;
13308  }
13309  }
13310  else
13311  {
13312  DiscrepancyFound = true;
13313  }
13314  }
13315  Utilities->CallLogPop(1512);
13316  return(!DiscrepancyFound);
13317 }
13318 
13319 // ---------------------------------------------------------------------------
13320 
13321 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13322 /*
13323  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13324  turn and for the overall sizes.
13325 */
13326 {
13327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13328  bool FoundFlag = false;
13329  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13330 
13331  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13332  {
13333  TPrefDirElement CheckElement = PrefDirVector.at(a);
13334  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13335  if(!FoundFlag)
13336  {
13337  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13338  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13339  }
13340  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13341  {
13342  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13343  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13344  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13345  }
13346  }
13347  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13348  {
13349  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13350  + " Caller=" + (AnsiString)Caller);
13351  }
13352  Utilities->CallLogPop(180);
13353 }
13354 
13355 // ---------------------------------------------------------------------------
13356 
13357 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13358  int &PrefDirPos3)
13359 /*
13360  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13361  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13362  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13363  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13364  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13365 */
13366 {
13367  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13368  AnsiString(VLoc));
13369  THVPair PrefDirMapKeyPair;
13370 
13371  PrefDirPos0 = -1;
13372  PrefDirPos1 = -1;
13373  PrefDirPos2 = -1;
13374  PrefDirPos3 = -1;
13375  FoundFlag = false;
13376  PrefDirMapKeyPair.first = HLoc;
13377  PrefDirMapKeyPair.second = VLoc;
13378  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13379 
13380  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13381  if(ItPair.first == ItPair.second) //none found
13382  {
13383  Utilities->CallLogPop(181);
13384  return;
13385  }
13386  else
13387  {
13388  FoundFlag = true;
13389  PrefDirPos0 = ItPair.first->second;
13390  ItPair.first++;
13391  if(ItPair.first == ItPair.second)
13392  {
13393  Utilities->CallLogPop(182); //only one found
13394  return;
13395  }
13396  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13397  {
13398  PrefDirPos1 = ItPair.first->second;
13399  }
13400  ItPair.first++;
13401  if(ItPair.first == ItPair.second)
13402  {
13403  Utilities->CallLogPop(183); //2 found
13404  return;
13405  }
13406  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13407  {
13408  PrefDirPos2 = ItPair.first->second;
13409  }
13410  ItPair.first++;
13411  if(ItPair.first == ItPair.second)
13412  {
13413  Utilities->CallLogPop(184); //3 found
13414  return;
13415  }
13416  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13417  {
13418  PrefDirPos3 = ItPair.first->second; //4 found
13419  }
13420  }
13421  Utilities->CallLogPop(185);
13422 }
13423 
13424 // ---------------------------------------------------------------------------
13425 
13426 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13427 { //not used after modified the pref dir checking function at v2.13.0
13428  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13429  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13430  try
13431  {
13432  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13433  + "," + AnsiString(LinkNumberPos));
13434  bool FoundFlag;
13435  int PD0, PD1, PD2, PD3;
13436  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13437  {
13438  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13439  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13440  PD0, PD1, PD2, PD3);
13441  if(!FoundFlag)
13442  {
13443  Utilities->CallLogPop(2282);
13444  return(false);
13445  }
13446  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13447  {
13448  if(PD0 > -1)
13449  {
13450  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13451  {
13452  LinkedPrefDirVectorNumber = PD0;
13453  Utilities->CallLogPop(2283);
13454  return(true);
13455  }
13456  }
13457  if(PD1 > -1)
13458  {
13459  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13460  {
13461  LinkedPrefDirVectorNumber = PD1;
13462  Utilities->CallLogPop(2284);
13463  return(true);
13464  }
13465  }
13466  }
13467  if(PD0 > -1)
13468  {
13469  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13470  {
13471  LinkedPrefDirVectorNumber = PD0;
13472  Utilities->CallLogPop(2285);
13473  return(true);
13474  }
13475  }
13476  if(PD1 > -1)
13477  {
13478  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13479  {
13480  LinkedPrefDirVectorNumber = PD1;
13481  Utilities->CallLogPop(2286);
13482  return(true);
13483  }
13484  }
13485  if(PD2 > -1)
13486  {
13487  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13488  {
13489  LinkedPrefDirVectorNumber = PD2;
13490  Utilities->CallLogPop(2287);
13491  return(true);
13492  }
13493  }
13494  if(PD3 > -1)
13495  {
13496  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13497  {
13498  LinkedPrefDirVectorNumber = PD3;
13499  Utilities->CallLogPop(2288);
13500  return(true);
13501  }
13502  }
13503  LinkedPrefDirVectorNumber = -1;
13504  Utilities->CallLogPop(2289);
13505  return(false);
13506  }
13507  else //buffer or continuation, no link at position 0 but not a failure
13508  {
13509  LinkedPrefDirVectorNumber = -1;
13510  Utilities->CallLogPop(2290);
13511  return(true);
13512  }
13513  }
13514  catch(const Exception &e) //non error catch
13515  {
13516  LinkedPrefDirVectorNumber = -1;
13517  Utilities->CallLogPop(2291);
13518  return(false);
13519  }
13520 }
13521 
13522 // ---------------------------------------------------------------------------
13523 
13524 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13525 { //not used after modified the pref dir checking function at v2.13.0
13526  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
13527  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13528  try
13529  {
13530  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
13531  + "," + AnsiString(LinkNumberPos));
13532  bool FoundFlag;
13533  int PD0, PD1, PD2, PD3;
13534  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13535  {
13536  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13537  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13538  PD0, PD1, PD2, PD3);
13539  if(!FoundFlag)
13540  {
13541  Utilities->CallLogPop(2468);
13542  return(false);
13543  }
13544  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13545  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
13546  if(PD0 > -1)
13547  {
13548  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
13549  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
13550  {
13551  LinkedPrefDirVectorNumber = PD0;
13552  Utilities->CallLogPop(2469);
13553  return(true);
13554  }
13555  }
13556  if(PD1 > -1)
13557  {
13558  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
13559  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
13560  {
13561  LinkedPrefDirVectorNumber = PD1;
13562  Utilities->CallLogPop(2470);
13563  return(true);
13564  }
13565  }
13566  LinkedPrefDirVectorNumber = -1;
13567  Utilities->CallLogPop(2471);
13568  return(false);
13569  }
13570  if(PD0 > -1)
13571  {
13572  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13573  {
13574  LinkedPrefDirVectorNumber = PD0;
13575  Utilities->CallLogPop(2472);
13576  return(true);
13577  }
13578  }
13579  if(PD1 > -1)
13580  {
13581  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13582  {
13583  LinkedPrefDirVectorNumber = PD1;
13584  Utilities->CallLogPop(2473);
13585  return(true);
13586  }
13587  }
13588  if(PD2 > -1)
13589  {
13590  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13591  {
13592  LinkedPrefDirVectorNumber = PD2;
13593  Utilities->CallLogPop(2474);
13594  return(true);
13595  }
13596  }
13597  if(PD3 > -1)
13598  {
13599  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13600  {
13601  LinkedPrefDirVectorNumber = PD3;
13602  Utilities->CallLogPop(2475);
13603  return(true);
13604  }
13605  }
13606  LinkedPrefDirVectorNumber = -1;
13607  Utilities->CallLogPop(2476);
13608  return(false);
13609  }
13610  else //buffer or continuation, no link at position 0 but not a failure
13611  {
13612  LinkedPrefDirVectorNumber = -1;
13613  Utilities->CallLogPop(2477);
13614  return(true);
13615  }
13616  }
13617  catch(const Exception &e) //non error catch
13618  {
13619  LinkedPrefDirVectorNumber = -1;
13620  Utilities->CallLogPop(2478);
13621  return(false);
13622  }
13623 }
13624 
13625 // ---------------------------------------------------------------------------
13626 
13628 {
13629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13630  bool FoundFlag; //not used
13631  int PD0, PD1, PD2, PD3;
13632  //recover all PDs at the H & V of PDPtr
13633  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13634 
13635  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13636  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13637 
13638  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13639  {
13640  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13641  {
13642  Utilities->CallLogPop(2292);
13643  return(true);
13644  }
13645  }
13646  if(PD1 > -1)
13647  {
13648  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13649  {
13650  Utilities->CallLogPop(2293);
13651  return(true);
13652  }
13653  }
13654  if(PD2 > -1)
13655  {
13656  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13657  {
13658  Utilities->CallLogPop(2294);
13659  return(true);
13660  }
13661  }
13662  if(PD3 > -1)
13663  {
13664  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13665  {
13666  Utilities->CallLogPop(2295);
13667  return(true);
13668  }
13669  }
13670  Utilities->CallLogPop(2296);
13671  return(false);
13672 }
13673 
13674 // ---------------------------------------------------------------------------
13675 
13676 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13677 /*
13678  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13679 */
13680 {
13681  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13682  PrefDirVector.push_back(LoadPrefDirElement);
13683  THVPair PrefDir4MultiMapKeyPair;
13684  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13685 
13686  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13687  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13688  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13689  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13690  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13691 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13692  Utilities->CallLogPop(186);
13693 }
13694 
13695 // ---------------------------------------------------------------------------
13696 
13697 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13698 /*
13699  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13700  4MultiMap if they are greater than the erased value.
13701 */
13702 {
13703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13704  bool FoundFlag;
13705 
13706  if(!PrefDirVector.empty())
13707  {
13708  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13709  if(!FoundFlag)
13710  {
13711  throw Exception("Failed to find PrefDir4MultiMap erase element");
13712  }
13713  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13714  PrefDir4MultiMap.erase(EraseIt);
13715  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13717  }
13718  Utilities->CallLogPop(187);
13719 }
13720 
13721 // ---------------------------------------------------------------------------
13722 
13723 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13724 /*
13725  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13726  4MultiMap if they are greater than the erased value.
13727 */
13728 {
13729  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13730  AnsiString(ErasedElementNumber));
13731  if(!PrefDir4MultiMap.empty())
13732  {
13733  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13734  {
13735  if(MapPtr->second > ErasedElementNumber)
13736  {
13737  MapPtr->second--;
13738  }
13739  }
13740  }
13741  Utilities->CallLogPop(1450);
13742 }
13743 
13744 // ---------------------------------------------------------------------------
13745 
13746 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13747 /*
13748  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13749  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13750  nothing is found this is an error but the error message is given in the calling function.
13751 */
13752 {
13753  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13754  FoundFlag = false;
13755  if(PrefDirVectorPosition >= PrefDirVector.size())
13756  {
13757  throw Exception("PrefDirVectorPosition out of range");
13758  }
13759  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13760  THVPair PrefDir4MultiMapKeyPair;
13761 
13762  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13763  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13764  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13765 
13766  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13767  if(ItPair.first == ItPair.second)
13768  {
13769  Utilities->CallLogPop(188);
13770  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13771  }
13772  else
13773  {
13774  if(ItPair.first->second == PrefDirVectorPosition)
13775  {
13776  FoundFlag = true;
13777  Utilities->CallLogPop(189);
13778  return(ItPair.first);
13779  }
13780  ItPair.first++;
13781  if(ItPair.first == ItPair.second)
13782  {
13783  Utilities->CallLogPop(190);
13784  return(ItPair.first); // nothing found
13785  }
13786  if(ItPair.first->second == PrefDirVectorPosition)
13787  {
13788  FoundFlag = true;
13789  Utilities->CallLogPop(191);
13790  return(ItPair.first);
13791  }
13792  ItPair.first++;
13793  if(ItPair.first == ItPair.second)
13794  {
13795  Utilities->CallLogPop(192);
13796  return(ItPair.first); // nothing found
13797  }
13798  if(ItPair.first->second == PrefDirVectorPosition)
13799  {
13800  FoundFlag = true;
13801  Utilities->CallLogPop(193);
13802  return(ItPair.first);
13803  }
13804  ItPair.first++;
13805  if(ItPair.first == ItPair.second)
13806  {
13807  Utilities->CallLogPop(194);
13808  return(ItPair.first); // nothing found
13809  }
13810  if(ItPair.first->second == PrefDirVectorPosition)
13811  {
13812  FoundFlag = true;
13813  Utilities->CallLogPop(195);
13814  return(ItPair.first);
13815  }
13816  }
13817  Utilities->CallLogPop(196);
13818  return(ItPair.first); // nothing found
13819 }
13820 
13821 // ---------------------------------------------------------------------------
13822 
13823 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13824 /*
13825  Although there may be up to four entries at one H & V position this function gets just one. It is
13826  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13827  at H & V.
13828 */
13829 {
13830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13831  THVPair PrefDir4MultiMapKeyPair;
13832 
13833  PrefDir4MultiMapKeyPair.first = HLoc;
13834  PrefDir4MultiMapKeyPair.second = VLoc;
13835  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13836 
13837  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13838  if(ItPair.first == ItPair.second) // nothing found
13839  {
13840  Utilities->CallLogPop(197);
13841  return(-1);
13842  }
13843  else
13844  {
13845  Utilities->CallLogPop(198);
13846  return(ItPair.first->second);
13847  }
13848 }
13849 
13850 // ---------------------------------------------------------------------------
13851 
13852 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13853 {
13854  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13855  bool ErasedFlag = false;
13856 
13857  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13858  {
13859  if(PrefDirSize() == 0)
13860  {
13861  Utilities->CallLogPop(1511);
13862  return;
13863  }
13864  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13865  {
13866  ErasedFlag = false;
13867  // use 'else' to ensure don't try to access an erased element
13868  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13869  {
13870  ErasePrefDirElementAt(11, x);
13871  ErasedFlag = true;
13872  }
13873  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13874  {
13875  ErasePrefDirElementAt(12, x);
13876  ErasedFlag = true;
13877  }
13878  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13879  {
13880  ErasePrefDirElementAt(13, x);
13881  ErasedFlag = true;
13882  }
13883  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13884  {
13885  ErasePrefDirElementAt(9, x);
13886  ErasedFlag = true;
13887  }
13888  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13889  {
13890  ErasePrefDirElementAt(10, x);
13891  ErasedFlag = true;
13892  }
13893  if(!ErasedFlag)
13894  {
13895  // don't use 'else' here as may be more than one that need decrementing
13896  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13897  {
13898  PrefDirVector.at(x).TrackVectorPosition--;
13899  }
13900  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13901  {
13902  PrefDirVector.at(x).Conn[0]--;
13903  }
13904  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13905  {
13906  PrefDirVector.at(x).Conn[1]--;
13907  }
13908  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13909  {
13910  PrefDirVector.at(x).Conn[2]--;
13911  }
13912  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13913  {
13914  PrefDirVector.at(x).Conn[3]--;
13915  }
13916  }
13917  }
13918  }
13919  Utilities->CallLogPop(1434);
13920 }
13921 
13922 // ---------------------------------------------------------------------------
13923 
13924 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13925 {
13926  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13927  OverallDistance = 0;
13928  OverallSpeedLimit = 0;
13929  LeadingPointsAtLastElement = false;
13930  if(PrefDirSize() == 0) // shouldn't be empty when this called
13931  {
13932  Utilities->CallLogPop(1491);
13933  return;
13934  }
13935  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13936  {
13937  LeadingPointsAtLastElement = true;
13938  Utilities->CallLogPop(1492);
13939  return;
13940  }
13941  for(unsigned int x = 0; x < PrefDirSize(); x++)
13942  {
13943  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13944  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13945  {
13946  OverallDistance += PrefDirElement.Length23;
13947  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13948  {
13949  if(x == 0)
13950  {
13951  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13952  }
13953  else
13954  {
13955  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13956  {
13957  OverallSpeedLimit = -1;
13958  }
13959  }
13960  }
13961  }
13962  else
13963  {
13964  OverallDistance += PrefDirElement.Length01;
13965  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13966  {
13967  if(x == 0)
13968  {
13969  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13970  }
13971  else
13972  {
13973  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13974  {
13975  OverallSpeedLimit = -1;
13976  }
13977  }
13978  }
13979  }
13980  }
13981  Utilities->CallLogPop(1529);
13982 }
13983 
13984 // ---------------------------------------------------------------------------
13985 
13986 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13987 {
13988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13989  if(PrefDirSize() == 0)
13990  {
13991  Utilities->CallLogPop(1564);
13992  return;
13993  }
13994  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13995  bool FoundFlag;
13997  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13998 
13999  while(MMIT != PrefDir4MultiMap.end())
14000  {
14001  HLoc = MMIT->first.first;
14002  VLoc = MMIT->first.second;
14003  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14004  H = HLoc - Track->GetHLocMin();
14005  V = VLoc - Track->GetVLocMin();
14006  // always found in order, any missing have PrefDirPosx == -1
14007  if(PrefDirPos0 > -1)
14008  {
14009  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14010  }
14011  if(PrefDirPos1 > -1)
14012  {
14013  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14014  }
14015  if(PrefDirPos2 > -1)
14016  {
14017  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14018  }
14019  if(PrefDirPos3 > -1)
14020  {
14021  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14022  }
14023  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14024  {
14025  // need to plot all 4 in order to obtain all the direction graphics
14026  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14027  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14028  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14029  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14030  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14031  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14032  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14033  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14034  MMIT++;
14035  MMIT++;
14036  MMIT++;
14037  MMIT++;
14038  }
14039  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14040  {
14041  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14042  {
14043  // 0 & 1 constitute the bidirectional PrefDir
14044  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14045  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14046  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14047  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14048  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14049  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14050  MMIT++;
14051  MMIT++;
14052  MMIT++;
14053  }
14054  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14055  {
14056  // 0 & 2 constitute the bidirectional PrefDir
14057  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14058  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14059  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14060  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14061  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14062  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14063  MMIT++;
14064  MMIT++;
14065  MMIT++;
14066  }
14067  else
14068  {
14069  // 1 & 2 constitute the bidirectional PrefDir
14070  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14071  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14072  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14073  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14074  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14075  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14076  MMIT++;
14077  MMIT++;
14078  MMIT++;
14079  }
14080  }
14081  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14082  {
14083  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14084  {
14085  // 0 & 1 constitute the bidirectional PrefDir
14086  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14087  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14088  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14089  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14090  MMIT++;
14091  MMIT++;
14092  }
14093  else
14094  {
14095  // 2 unidirectional PrefDirs
14096  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14097  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14098  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14099  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14100  MMIT++;
14101  MMIT++;
14102  }
14103  }
14104  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14105  {
14106  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14107  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14108  MMIT++;
14109  }
14110  }
14111  Utilities->CallLogPop(1565);
14112 }
14113 
14114 // ---------------------------------------------------------------------------
14115 
14116 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14117 /*
14118  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14119  level crossing, signals with wrong direction set, or buffers.
14120 */
14121 {
14122  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14123  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14124  bool FoundFlag;
14126  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14127 
14128  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14129  ElementIn.VLoc)))
14130  {
14131  Utilities->CallLogPop(1982);
14132  return(false);
14133  }
14134  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14135  {
14136  Utilities->CallLogPop(1983);
14137  return(false);
14138  }
14139 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14140  {
14141  Utilities->CallLogPop(1995);
14142  return(false);
14143  }
14144 */
14145 // Now check that there is only a single prefdir set
14146  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14147 // always found in order, any missing have PrefDirPosx == -1
14148  if(PrefDirPos0 > -1)
14149  {
14150  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14151  }
14152  if(PrefDirPos1 > -1)
14153  {
14154  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14155  }
14156  if(PrefDirPos2 > -1)
14157  {
14158  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14159  }
14160  if(PrefDirPos3 > -1)
14161  {
14162  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14163  }
14164  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14165  {
14166  Utilities->CallLogPop(1984);
14167  return(false);
14168  }
14169  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14170  {
14171  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14172  {
14173  Utilities->CallLogPop(1985);
14174  return(false);
14175  }
14176  else
14177  {
14178  Utilities->CallLogPop(1986);
14179  return(true);
14180  }
14181  }
14182  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14183  {
14184  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14185  {
14186  Utilities->CallLogPop(1987);
14187  return(false);
14188  }
14189  else
14190  {
14191  Utilities->CallLogPop(1988);
14192  return(true);
14193  }
14194  }
14195  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14196  {
14197  if(PrefDirElement0.XLinkPos == EntryPos)
14198  {
14199  Utilities->CallLogPop(1989);
14200  return(false);
14201  }
14202  else
14203  {
14204  Utilities->CallLogPop(1990);
14205  return(true);
14206  }
14207  }
14208  else
14209  {
14210  Utilities->CallLogPop(1991);
14211  return(false); // none found
14212  }
14213 }
14214 
14215 // ---------------------------------------------------------------------------
14216 
14218 {
14219 /* //Added at v2.1.0
14220  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14221  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14222  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14223  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14224  and can be modelled better anyway.
14225 
14226  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14227  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14228  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14229  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14230  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14231  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14232 */
14233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14234  ElementIn.VLoc + "," + XLink);
14235  int TrackVecPos;
14236  bool TrackFoundFlag;
14237  TTrackElement TempTrackElement;
14238 
14239  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14240  {
14241  Utilities->CallLogPop(2047);
14242  return(false);
14243  }
14244 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14245  if(XLink == 1)
14246  {
14247  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14248  if(TrackFoundFlag)
14249  {
14250  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14251  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14252  {
14253  Utilities->CallLogPop(2048);
14254  return(true);
14255  }
14256  }
14257  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14258  if(TrackFoundFlag)
14259  {
14260  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14261  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14262  {
14263  Utilities->CallLogPop(2049);
14264  return(true);
14265  }
14266  }
14267  }
14268 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14269  if(XLink == 3)
14270  {
14271  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14272  if(TrackFoundFlag)
14273  {
14274  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14275  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14276  {
14277  Utilities->CallLogPop(2050);
14278  return(true);
14279  }
14280  }
14281  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14282  if(TrackFoundFlag)
14283  {
14284  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14285  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14286  {
14287  Utilities->CallLogPop(2051);
14288  return(true);
14289  }
14290  }
14291  }
14292 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14293  if(XLink == 7)
14294  {
14295  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14296  if(TrackFoundFlag)
14297  {
14298  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14299  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14300  {
14301  Utilities->CallLogPop(2052);
14302  return(true);
14303  }
14304  }
14305  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14306  if(TrackFoundFlag)
14307  {
14308  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14309  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14310  {
14311  Utilities->CallLogPop(2053);
14312  return(true);
14313  }
14314  }
14315  }
14316 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14317  if(XLink == 9)
14318  {
14319  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14320  if(TrackFoundFlag)
14321  {
14322  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14323  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14324  {
14325  Utilities->CallLogPop(2054);
14326  return(true);
14327  }
14328  }
14329  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14330  if(TrackFoundFlag)
14331  {
14332  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14333  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14334  {
14335  Utilities->CallLogPop(2055);
14336  return(true);
14337  }
14338  }
14339  }
14340  Utilities->CallLogPop(2056);
14341  return(false);
14342 }
14343 
14344 // ---------------------------------------------------------------------------
14345 
14346 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14347 {
14348 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14349  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14350  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14351  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14352  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14353 */
14354  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14356  bool FoundFlag, ContFlag, FoundElements = false;
14357  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14358  TPrefDirElement NextElement;
14359 
14360  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14361  {
14362  LastIteratorValue++;
14363  ContFlag = false;
14364  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14365  {
14366  continue;
14367  }
14368 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14369  {
14370  continue;
14371  }
14372 */
14373 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14374  // found a potential route start point
14375  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14376  {
14377  continue;
14378  }
14379  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14380  {
14381  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14382  if(PDVIt->TrackType == Continuation)
14383  {
14384  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14385  {
14386  continue;
14387  }
14388  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14389  {
14390  continue;
14391  }
14392  }
14393  StartElement = *PDVIt;
14394 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14395  // diverging track on which there was no pref dir. See below for 2 required changes.
14396  }
14397  else
14398  {
14399  continue;
14400  }
14401  // now track along until find a signal or continuation, checking validity for each element
14402  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14403  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14404  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14405  if(PrefDirPos0 == -1) // no continuing prefdir
14406  {
14407  continue;
14408  }
14409  bool NextElementFoundFlag = false;
14410  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14411  {
14412  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14413  NextElementFoundFlag = true;
14414  }
14415  if(PrefDirPos1 > -1)
14416  {
14417  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14418  {
14419  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14420  NextElementFoundFlag = true;
14421  }
14422  }
14423  if(PrefDirPos2 > -1)
14424  {
14425  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14426  {
14427  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14428  NextElementFoundFlag = true;
14429  }
14430  }
14431  if(PrefDirPos3 > -1)
14432  {
14433  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14434  {
14435  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14436  NextElementFoundFlag = true;
14437  }
14438  }
14439  if(!NextElementFoundFlag)
14440  {
14441  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14442 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14443  }
14444  while(true)
14445  {
14446  // check validity
14447  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14448  {
14449  ContFlag = true;
14450  break;
14451  }
14452  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14453  {
14454  ContFlag = true;
14455  break;
14456  }
14457  // check if in a route, providing not a signal, as a signal might be at the start of a route
14458  if(NextElement.TrackType != SignalPost)
14459  {
14460  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14461  {
14462  ContFlag = true;
14463  break;
14464  }
14465  }
14466  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14467  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
14468  {
14469  EndElement = NextElement;
14470  break;
14471  }
14472  // get the next element in the sequence
14473  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14474  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14475  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14476  if(PrefDirPos0 == -1) // no continuing prefdir
14477  {
14478  ContFlag = true;
14479  break;
14480  }
14481  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14482  {
14483  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14484  continue;
14485  }
14486  if(PrefDirPos1 > -1)
14487  {
14488  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14489  {
14490  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14491  continue;
14492  }
14493  }
14494  if(PrefDirPos2 > -1)
14495  {
14496  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14497  {
14498  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14499  continue;
14500  }
14501  }
14502  if(PrefDirPos3 > -1)
14503  {
14504  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14505  {
14506  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14507  continue;
14508  }
14509  }
14510  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14511  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14512  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14513  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14514  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14515  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14516  {
14517  ContFlag = true;
14518  break;
14519  }
14520  else
14521  {
14522  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14523  // could drop the bridge test but keep it to show the change history
14524  break;
14525 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14526  }
14527  }
14528  if(ContFlag)
14529  {
14530  continue;
14531  }
14532  // else have start and end elements set & all elements valid, so set up the route segment
14533  FoundElements = true;
14534  break;
14535  }
14536  if(FoundElements)
14537  {
14538  Utilities->CallLogPop(1992);
14539  return(true);
14540  }
14541  else
14542  {
14543  Utilities->CallLogPop(1993);
14544  return(false);
14545  }
14546 }
14547 
14548 // ---------------------------------------------------------------------------
14549 // TOneRoute
14550 // ---------------------------------------------------------------------------
14551 
14552 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14553 {
14554 /* General:
14555  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14556  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14557  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14558  route will use automatic signals or not.
14559  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14560  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14561  elements, so additional work is needed to complete all their members before they are ready for conversion into
14562  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14563  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14564  ConvertAndAdd.......
14565 */
14566  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14567  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14568  ClearRoute();
14569  int TrackVectorPosition;
14570  TTrackElement TrackElement;
14571  TPrefDirElement FirstElement, LastElement;
14572 
14573  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14574  {
14575  Utilities->CallLogPop(199);
14576  return(false);
14577  }
14578  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14579  {
14580  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14581  Utilities->CallLogPop(1996);
14582  return(false);
14583  }
14584  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14585  {
14586  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14587  Utilities->CallLogPop(200);
14588  return(false);
14589  }
14590  if(Track->IsLCAtHV(18, HLoc, VLoc))
14591  {
14592  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14593  Utilities->CallLogPop(1909);
14594  return(false);
14595  }
14596 // check if selected a train & disallow if so
14597  if(TrackElement.TrainIDOnElement > -1)
14598  {
14599  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14600  Utilities->CallLogPop(202);
14601  return(false);
14602  }
14603 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14604  TPrefDirElement PrefDirElement;
14605  int LockedVectorNumber;
14606 
14607  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14608  {
14609  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14610  Utilities->CallLogPop(203);
14611  return(false);
14612  }
14613  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14614  {
14615  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14616  Utilities->CallLogPop(204);
14617  return(false);
14618  }
14620  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14621 // signal in an autosig route & follow with a non-autosig route
14622 
14623  TPrefDirElement BlankElement;
14624 
14625  StartElement1 = BlankElement;
14626  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14627 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14628  bool InPrefDirFlag = false;
14629 
14630  bool FoundFlag;
14631  int PrefDirPos0 = -1;
14632  int PrefDirPos1 = -1;
14633  int PrefDirPos2 = -1;
14634  int PrefDirPos3 = -1;
14635 
14637  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14638  int PrefDirVecPos[4] =
14639  {
14640  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14641  };
14642 
14643  for(int x = 0; x < 4; x++)
14644  {
14645  int b = PrefDirVecPos[x];
14646  if(b > -1)
14647  {
14648  // only allow the appropriate exit route to be searched
14649  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14650  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14651  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14652  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14653  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14654  {
14655  InPrefDirFlag = true;
14656  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14657  if(AutoSigsFlag)
14658  {
14659  StartElement1.AutoSignals = true;
14660  }
14661  StartElement1.PrefDirRoute = true;
14662  }
14663  }
14664  }
14665 
14666  if(!InPrefDirFlag)
14667  {
14668  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14669  Utilities->CallLogPop(205);
14670  return(false);
14671  }
14672 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14674  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14675 
14676  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14677  {
14678  throw Exception("Selection in two routes - should never happen!");
14679  }
14680  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14681  {
14682  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14683  {
14684  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14685  Utilities->CallLogPop(206);
14686  return(false);
14687  }
14688  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14689  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14690  {
14691  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14692  Utilities->CallLogPop(207);
14693  return(false);
14694  }
14695  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14696  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14697  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14698  {
14699  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14700  Utilities->CallLogPop(208);
14701  return(false);
14702  }
14703  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14705  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14706  if(AutoSigsFlag)
14707  {
14708  StartElement1.AutoSignals = true;
14709  }
14710  StartElement1.PrefDirRoute = true;
14712  Utilities->CallLogPop(209);
14713  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14714  }
14715 
14716  else // no route started
14717  {
14718 // check if selected position is adjacent to start or end of an existing route and disallow
14719  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14720  {
14721  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14722  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14723  {
14724  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14725  Utilities->CallLogPop(210);
14726  return(false);
14727  }
14728  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14729  {
14730  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14731  Utilities->CallLogPop(211);
14732  return(false);
14733  }
14734  }
14735 
14736 // check if it's adjacent to end of an existing route,
14737  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14738  {
14740  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14741  {
14742  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14743  Utilities->CallLogPop(212);
14744  return(false);
14745  }
14746  }
14747  SearchVector.push_back(StartElement1);
14748  Utilities->CallLogPop(213);
14749  return(true);
14750  }
14751 }
14752 
14753 // ---------------------------------------------------------------------------
14754 
14755 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14756  IDInt &ReqPosRouteID, bool &PointsChanged)
14757 
14758 /*
14759  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14760 
14761  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14762  this being set to -1 for not used.
14763  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14764  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14765  Check correct type of element - signal/buffers/continuation.
14766  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14767  EndElement2 corresponding to the 2 possible PrefDir elements).
14768  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14769  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14770  linked forward to another route.
14771  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14772  for same position as start should cover this)
14773 
14774  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14775  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14776  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14777  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14778  If the search fails then return false.
14779  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14780  in the SearchVector to ensure it's entered as part of the new route.
14781  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14782  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14783  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14784  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14785  so return false, with an appropriate message if ConsecSignalsRoute set.
14786 */
14787 
14788 {
14789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14790  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14791  int EndPosition; // the position selected
14792  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
14793 
14794  Track->LCFoundInAutoSigsRoute = false;
14796  TotalSearchCount = 0;
14797  ReqPosRouteID = IDInt(-1); // default value for not used
14798  TTrackElement TrackElement;
14799  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14800  // given element as can't select 2-track elements
14801  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14802  {
14803  Utilities->CallLogPop(214);
14804  return(false);
14805  }
14806  if(Track->IsLCAtHV(19, HLoc, VLoc))
14807  {
14808  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14809  Utilities->CallLogPop(1908);
14810  return(false);
14811  }
14812 // cancel selection if on original start element
14813  if(EndPosition == StartRoutePosition)
14814  {
14815  Utilities->CallLogPop(215);
14816  return(false);
14817  }
14818  if(AutoSigsFlag)
14819  {
14820  if(TrackElement.TrackType == Buffers)
14821  {
14822  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14823  Utilities->CallLogPop(216);
14824  return(false);
14825  }
14826  }
14827  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14828  {
14829  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14830  Utilities->CallLogPop(217);
14831  return(false);
14832  }
14833 // check if train on element
14834  if(TrackElement.TrainIDOnElement > -1)
14835  {
14836  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14837  Utilities->CallLogPop(219);
14838  return(false);
14839  }
14840 // disallow if not in EveryPrefDir & set EndElement(s)
14841  bool InPrefDirFlag = false;
14842 
14843  bool FoundFlag;
14844  int PrefDirPos0 = -1;
14845  int PrefDirPos1 = -1;
14846  int PrefDirPos2 = -1;
14847  int PrefDirPos3 = -1;
14848 
14849  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14850  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14851  int PrefDirVecPos[4] =
14852  {
14853  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14854  };
14855 
14856  for(int x = 0; x < 4; x++)
14857  {
14858  int b = PrefDirVecPos[x];
14859  if(b > -1)
14860  {
14861  InPrefDirFlag = true;
14862  if(EndElement1.TrackVectorPosition == -1)
14863  {
14864  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14865  }
14866  else
14867  {
14868  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14869  }
14870  }
14871  }
14872  if(!InPrefDirFlag)
14873  {
14874  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14875  Utilities->CallLogPop(220);
14876  return(false);
14877  }
14878 // check if in an existing route - can't be a bridge so can use a simple 'find'
14879 // bool InRoute = false;
14881  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14882 
14883  if(RoutePair.first > -1)
14884  {
14885  if(RoutePair.second != 0) // not first element in existing route so no good
14886  {
14887  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14888  Utilities->CallLogPop(221);
14889  return(false);
14890  }
14891  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14892 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14893  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14894  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14895  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14896  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14897  {
14898  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14899  Utilities->CallLogPop(222);
14900  return(false);
14901  }
14902  EndElement1 = RouteElement;
14903  EndElement2 = BlankElement; // only need the route element
14904  EndPosition = EndElement1.TrackVectorPosition;
14905  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14906  }
14907 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14908 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14909 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14910 
14911  if(EndElement1.HLoc >= StartElement1.HLoc)
14912  {
14914  SearchLimitHighH = EndElement1.HLoc + 15;
14915  }
14916  else
14917  {
14918  SearchLimitLowH = EndElement1.HLoc - 15;
14920  }
14921  if(EndElement1.VLoc >= StartElement1.VLoc)
14922  {
14924  SearchLimitHighV = EndElement1.VLoc + 15;
14925  }
14926  else
14927  {
14928  SearchLimitLowV = EndElement1.VLoc - 15;
14930  }
14931 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14932  check & TotalSearchCounts check
14933  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14934  {
14935  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14936  Utilities->CallLogPop(1693);
14937  return false;
14938  }
14939 */
14940 // check if adjacent to start and disallow
14941  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14942  {
14944  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14945 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14946 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14947  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14948  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14949  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14950  {
14951  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14952  Utilities->CallLogPop(223);
14953  return(false);
14954  }
14955 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14956 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14957  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14958  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14959  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14960  {
14961  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14962  Utilities->CallLogPop(224);
14963  return(false);
14964  }
14965 // check if adjacent to end of a route & disallow
14967  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14968  {
14969  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14970  Utilities->CallLogPop(225);
14971  return(false);
14972  }
14973  }
14974 
14975 // check for same route as start element
14977  {
14978  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14979  Utilities->CallLogPop(226);
14980  return(false);
14981  }
14982 // check for a looping route
14983  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14984  {
14986  {
14987  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14988  Utilities->CallLogPop(1844);
14989  return(false);
14990  }
14991  }
14992 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14993 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14994 // and don't want to add it again
14995  if(StartSelectionRouteID > -1)
14996  {
14997  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14998  AutoSigsFlag, false))
14999  {
15000  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15001  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15002  {
15003  if(NewFailedPointsTVPos > -1)
15004  {
15005  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15006  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15007  " failed during route setting.");
15008  Utilities->CallLogPop(2488);
15009  return(false);
15010  }
15011  PointsChanged = true;
15012  }
15013  Utilities->CallLogPop(227);
15014  return(true);
15015  }
15016  else if(!Track->SuppressRouteFailMessage)
15017  {
15018  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15020  Utilities->CallLogPop(228);
15021  return(false);
15022  }
15023  }
15024  else
15025  {
15026 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15027 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15028 
15029 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15030 // note that a blank element will have XLinkPos set to -1
15031  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15032  {
15033  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15034  AutoSigsFlag, false))
15035  {
15036  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15037  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15038  {
15039  if(NewFailedPointsTVPos > -1)
15040  {
15041  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15042  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15043  " failed during route setting.");
15044  Utilities->CallLogPop(2490);
15045  return(false);
15046  }
15047  PointsChanged = true;
15048  }
15049  Utilities->CallLogPop(229);
15050  return(true);
15051  }
15052  else
15053  {
15055  {
15057  }
15058  Utilities->CallLogPop(230);
15059  return(false);
15060  }
15061  }
15062  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15063  {
15064  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15065  AutoSigsFlag, false))
15066  {
15067  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15068  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15069  {
15070  if(NewFailedPointsTVPos > -1)
15071  {
15072  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15073  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15074  " failed during route setting.");
15075  Utilities->CallLogPop(2492);
15076  return(false);
15077  }
15078  PointsChanged = true;
15079  }
15080  Utilities->CallLogPop(231);
15081  return(true);
15082  }
15083  else
15084  {
15086  {
15088  }
15089  Utilities->CallLogPop(232);
15090  return(false);
15091  }
15092  }
15093  // now start off in the best direction
15094  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15095  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15096  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15097  // unless new problems are found.
15098  if(StartElement1.XLinkPos == BestPos)
15099  {
15100  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15101  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15102  AutoSigsFlag, false))
15103  {
15104  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15105  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15106  {
15107  if(NewFailedPointsTVPos > -1)
15108  {
15109  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15110  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15111  " failed during route setting.");
15112  Utilities->CallLogPop(2494);
15113  return(false);
15114  }
15115  PointsChanged = true;
15116  }
15117  Utilities->CallLogPop(233);
15118  return(true);
15119  }
15120  else if(StartElement2.TrackVectorPosition > -1)
15121  {
15122  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15123  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15124  AutoSigsFlag, false))
15125  {
15126  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15127  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15128  {
15129  if(NewFailedPointsTVPos > -1)
15130  {
15131  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15132  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15133  " failed during route setting.");
15134  Utilities->CallLogPop(2496);
15135  return(false);
15136  }
15137  PointsChanged = true;
15138  }
15139  Utilities->CallLogPop(234);
15140  return(true);
15141  }
15142  }
15143  }
15144  else if(StartElement2.TrackVectorPosition > -1)
15145  {
15146  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15147  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15148  AutoSigsFlag, false))
15149  {
15150  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15151  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15152  {
15153  if(NewFailedPointsTVPos > -1)
15154  {
15155  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15156  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15157  " failed during route setting.");
15158  Utilities->CallLogPop(2498);
15159  return(false);
15160  }
15161  PointsChanged = true;
15162  }
15163  Utilities->CallLogPop(1857);
15164  return(true);
15165  }
15166  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15167  AutoSigsFlag, false))
15168  {
15169  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15170  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15171  {
15172  if(NewFailedPointsTVPos > -1)
15173  {
15174  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15175  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15176  " failed during route setting.");
15177  Utilities->CallLogPop(2500);
15178  return(false);
15179  }
15180  PointsChanged = true;
15181  }
15182  Utilities->CallLogPop(1858);
15183  return(true);
15184  }
15185  }
15186  else if(StartElement1.XLinkPos == (1 - BestPos))
15187  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15188  {
15189  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15190  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15191  AutoSigsFlag, false))
15192  {
15193  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15194  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15195  {
15196  if(NewFailedPointsTVPos > -1)
15197  {
15198  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15199  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15200  " failed during route setting.");
15201  Utilities->CallLogPop(2502);
15202  return(false);
15203  }
15204  PointsChanged = true;
15205  }
15206  Utilities->CallLogPop(1864);
15207  return(true);
15208  }
15209  }
15210  }
15212  {
15214  }
15215  Utilities->CallLogPop(235);
15216  return(false);
15217 }
15218 
15219 // ---------------------------------------------------------------------------
15220 
15221 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15222 {
15223  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15224  if(PrefDirSize() == 0)
15225  {
15226  Utilities->CallLogPop(1704);
15227  return;
15228  }
15229  for(unsigned int x = 0; x < PrefDirSize(); x++)
15230  {
15231  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15232  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15233  {
15234  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15235  TempPrefDirElement.EXGraphicPtr);
15236  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15237  {
15238  if(x == 0)
15239  {
15240  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15241  TempPrefDirElement.EntryDirectionGraphicPtr);
15242  }
15243  if(x == (PrefDirSize() - 1))
15244  {
15245  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15246  TempPrefDirElement.EntryDirectionGraphicPtr);
15247  }
15248  }
15249  }
15250  }
15251 
15252  Utilities->CallLogPop(1705);
15253 }
15254 
15255 // ---------------------------------------------------------------------------
15256 
15257 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15258  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15259 /*
15260  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15261  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15262  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15263  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15264  Return false if any element (apart from RequiredPosition) is on an existing route.
15265  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15266 
15267  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15268  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15269  added during the function so as to leave it exactly as it was on entering, then return false).
15270  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15271  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15272  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15273  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15274  the route number that the searched-for element is the start of if any, and set to -1 if no
15275  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15276  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15277  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15278  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15279 
15280  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15281  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15282  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15283  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15284  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15285  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15286  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15287  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15288  or if train on element (unless a bridge & train on different track).
15289  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15290  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15291  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15292  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15293  AutoSignals member set if AutoSigsFlag set, then return true.
15294  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15295 
15296  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15297  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15298  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15299  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15300  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15301  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15302  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15303 
15304  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15305  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15306 */
15307 
15308 {
15309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15310  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15311  AnsiString((short)AutoSigsFlag));
15312  int VectorCount = 0;
15313  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15314 
15315 // check for a fouled diagonal for first element. Added for v1.3.2
15316  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15317  {
15318  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15319  {
15320  for(int x = 0; x < VectorCount; x++)
15321  {
15322  SearchVector.erase(SearchVector.end() - 1);
15323  }
15324  Utilities->CallLogPop(2043);
15325  return(false);
15326  }
15327  }
15328  bool FirstPass = true;
15329 
15330  while(true)
15331  {
15332  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15333  {
15334  Track->LCFoundInAutoSigsRoute = true;
15335  }
15336  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15337  {
15338  for(int x = 0; x < VectorCount; x++)
15339  {
15340  SearchVector.erase(SearchVector.end() - 1);
15341  }
15342  Utilities->CallLogPop(1926);
15343  return(false);
15344  }
15345  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15346  {
15347  for(int x = 0; x < VectorCount; x++)
15348  {
15349  SearchVector.erase(SearchVector.end() - 1);
15350  }
15351  Utilities->CallLogPop(236);
15352  return(false);
15353  }
15354  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15355  // reached a valid signal that isn't the required position, user should always select the next
15356  // signal in a route when ConsecSignals is true so have to fail
15357  // won't affect recurive searches as for them the first pass element is always a point
15358  {
15359  for(int x = 0; x < VectorCount; x++)
15360  {
15361  SearchVector.erase(SearchVector.end() - 1);
15362  }
15363  Utilities->CallLogPop(237);
15364  return(false);
15365  }
15366  FirstPass = false;
15367  int NextPosition = PrefDirElement.Conn[XLinkPos];
15368  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15369  TPrefDirElement SearchElement(NextTrackElement);
15370  SearchElement.TrackVectorPosition = NextPosition;
15371  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15372  SearchElement.ELinkPos = NextELinkPos;
15373  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15374  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15375  int NextXLinkPos;
15376  if(SearchElement.ELinkPos == 0)
15377  {
15378  NextXLinkPos = 1;
15379  }
15380  if(SearchElement.ELinkPos == 1)
15381  {
15382  NextXLinkPos = 0;
15383  }
15384  if(SearchElement.ELinkPos == 2)
15385  {
15386  NextXLinkPos = 3;
15387  }
15388  if(SearchElement.ELinkPos == 3)
15389  {
15390  NextXLinkPos = 2;
15391  }
15392  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15393  {
15394  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15395 // note that may be buffers, continuation or gap
15396  SearchElement.XLinkPos = NextXLinkPos;
15397  }
15398 
15399 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15400 
15401 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15402  for(unsigned int x = 0; x < SearchVector.size(); x++)
15403  {
15404  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15405  {
15406  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15407  // OK if a bridge & routes on different tracks
15408  {
15409  for(int x = 0; x < VectorCount; x++)
15410  {
15411  SearchVector.erase(SearchVector.end() - 1);
15412  }
15413  Utilities->CallLogPop(238);
15414  return(false);
15415  }
15416  }
15417  }
15418 
15419 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15420  TAllRoutes::TRouteElementPair SecondPair;
15422  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15423  if(RoutePair.first > -1)
15424  {
15425  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15426  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15427  RoutePair.second).ELinkPos)))
15428  {
15429  // still OK if start of an expected route
15430  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15431  {
15432  for(int x = 0; x < VectorCount; x++)
15433  {
15434  SearchVector.erase(SearchVector.end() - 1);
15435  }
15436  Utilities->CallLogPop(239);
15437  return(false); // only allow for start of an expected route
15438  }
15439  }
15440  }
15441  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15442  {
15443  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15444  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15445  SecondPair.second).ELinkPos)))
15446  {
15447  // still OK if start of an expected route
15448  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15449  {
15450  for(int x = 0; x < VectorCount; x++)
15451  {
15452  SearchVector.erase(SearchVector.end() - 1);
15453  }
15454  Utilities->CallLogPop(240);
15455  return(false); // only allow for start of an expected route
15456  }
15457  }
15458  }
15459 // check if a train on element, unless a bridge & train on different track
15460 // OK of same train as start element - no drop this
15461 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15462  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15463  {
15464  for(int x = 0; x < VectorCount; x++)
15465  {
15466  SearchVector.erase(SearchVector.end() - 1);
15467  }
15468  Utilities->CallLogPop(241);
15469  return(false);
15470  }
15471  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15472  {
15473  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
15474  {
15475  for(int x = 0; x < VectorCount; x++)
15476  {
15477  SearchVector.erase(SearchVector.end() - 1);
15478  }
15479  Utilities->CallLogPop(242);
15480  return(false);
15481  }
15482  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
15483  {
15484  for(int x = 0; x < VectorCount; x++)
15485  {
15486  SearchVector.erase(SearchVector.end() - 1);
15487  }
15488  Utilities->CallLogPop(243);
15489  return(false);
15490  }
15491  }
15492 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15493  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15494  {
15495  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15496  {
15497  for(int x = 0; x < VectorCount; x++)
15498  {
15499  SearchVector.erase(SearchVector.end() - 1);
15500  }
15501  Utilities->CallLogPop(244);
15502  return(false);
15503  }
15504  }
15505 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15506 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15507  bool InPrefDirFlag = false;
15508  PrefDirElement1 = BlankElement;
15509  PrefDirElement2 = BlankElement;
15510 
15511  bool FoundFlag;
15512  int PrefDirPos0 = -1;
15513  int PrefDirPos1 = -1;
15514  int PrefDirPos2 = -1;
15515  int PrefDirPos3 = -1;
15517  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15518  int PrefDirVecPos[4] =
15519  {
15520  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15521  };
15522  for(int x = 0; x < 4; x++)
15523  {
15524  int b = PrefDirVecPos[x];
15525  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15526  {
15527  InPrefDirFlag = true;
15528  if(PrefDirElement1.TrackVectorPosition == -1)
15529  {
15530  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15531  }
15532  else
15533  {
15534  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15535  }
15536  }
15537  }
15538  if(!InPrefDirFlag)
15539  {
15540  for(int x = 0; x < VectorCount; x++)
15541  {
15542  SearchVector.erase(SearchVector.end() - 1);
15543  }
15544  Utilities->CallLogPop(245);
15545  return(false);
15546  }
15547 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15548 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15549 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15551  {
15552  for(int x = 0; x < VectorCount; x++)
15553  {
15554  SearchVector.erase(SearchVector.end() - 1);
15555  }
15556  Utilities->CallLogPop(1690);
15557  return(false);
15558  }
15559 // check if found it
15560  if(SearchElement.TrackVectorPosition == RequiredPosition)
15561  {
15562 // need to ensure a signal/buffer/continuation
15563  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15564  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15565  {
15566  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15568  for(int x = 0; x < VectorCount; x++)
15569  {
15570  SearchVector.erase(SearchVector.end() - 1);
15571  }
15572  Utilities->CallLogPop(246);
15573  return(false);
15574  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15575 
15576  if(AutoSigsFlag)
15577  {
15578  PrefDirElement1.AutoSignals = true;
15579  }
15580  PrefDirElement1.PrefDirRoute = true;
15582  {
15584  {
15585  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15587  }
15588  for(int x = 0; x < VectorCount; x++)
15589  {
15590  SearchVector.erase(SearchVector.end() - 1);
15591  }
15592  Utilities->CallLogPop(1928);
15593  return(false);
15594  }
15595  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15596  VectorCount++; // not really needed but include for tidyness
15597  TotalSearchCount++;
15598  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0
15599  {
15600  for(int x = 0; x < VectorCount; x++)
15601  {
15602  SearchVector.erase(SearchVector.end() - 1);
15603  }
15604  Utilities->CallLogPop(2522);
15605  return(false);
15606  }
15607  Utilities->CallLogPop(247);
15608  return(true);
15609  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15610 
15611 // check if a buffer or continuation (end of search on this leg if not found by now)
15612  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15613  {
15614  for(int x = 0; x < VectorCount; x++)
15615  {
15616  SearchVector.erase(SearchVector.end() - 1);
15617  }
15618  Utilities->CallLogPop(248);
15619  return(false);
15620  }
15621 // check if SearchVector exceeds a size of 150
15622  if(SearchVector.size() > 150)
15623  {
15624  for(int x = 0; x < VectorCount; x++)
15625  {
15626  SearchVector.erase(SearchVector.end() - 1);
15627  }
15628  Utilities->CallLogPop(1420);
15629  return(false);
15630  }
15631 //deal with failed points, added at v2.13.0
15632  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
15633  {
15634  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
15635  {
15636  SearchElement.XLinkPos = 1;
15637  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15638  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15639  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15640  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15641  }
15642  else
15643  {
15644  SearchElement.XLinkPos = 3;
15645  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15646  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15647  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15648  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15649  }
15650  }
15651  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
15652  {
15653  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
15654  {
15655  for(int x = 0; x < VectorCount; x++)
15656  {
15657  SearchVector.erase(SearchVector.end() - 1);
15658  }
15659  Utilities->CallLogPop(2514);
15660  return(false);
15661  }
15662  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
15663  {
15664  for(int x = 0; x < VectorCount; x++)
15665  {
15666  SearchVector.erase(SearchVector.end() - 1);
15667  }
15668  Utilities->CallLogPop(2515);
15669  return(false);
15670  }
15671  }
15672 // check if reached a non-failed leading point
15673  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
15674  {
15675 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15676  int SearchPos1 = SearchElement.Attribute + 1;
15677  int SearchPos2;
15678  if(SearchPos1 == 2)
15679  {
15680  SearchPos1++;
15681  }
15682  if(SearchPos1 == 1)
15683  {
15684  SearchPos2 = 3;
15685  }
15686  else
15687  {
15688  SearchPos2 = 1;
15689  }
15690  SearchElement.XLink = SearchElement.Link[SearchPos1];
15691  SearchElement.XLinkPos = SearchPos1;
15692  InPrefDirFlag = false;
15693  if(SearchElement.XLink == PrefDirElement1.XLink)
15694  {
15695  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15696  InPrefDirFlag = true;
15697  }
15698  else if(SearchElement.XLink == PrefDirElement2.XLink)
15699  {
15700  SearchElement = PrefDirElement2;
15701  InPrefDirFlag = true;
15702  }
15703 // push element with XLink set to position [SearchPos1] if on a PrefDir
15704  if(InPrefDirFlag)
15705  {
15706 // check for a fouled diagonal for leading point for XLinkPos == 1)
15707  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15708  {
15709  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15710  {
15711  for(int x = 0; x < VectorCount; x++)
15712  {
15713  SearchVector.erase(SearchVector.end() - 1);
15714  }
15715  Utilities->CallLogPop(249);
15716  return(false);
15717  }
15718  }
15719  if(AutoSigsFlag)
15720  {
15721  SearchElement.AutoSignals = true;
15722  }
15723  SearchElement.PrefDirRoute = true;
15724  SearchVector.push_back(SearchElement);
15725  VectorCount++;
15726  TotalSearchCount++;
15727 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15728  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15729  AutoSigsFlag, true))
15730  {
15732  {
15734  {
15735  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15737  }
15738  for(int x = 0; x < VectorCount; x++)
15739  {
15740  SearchVector.erase(SearchVector.end() - 1);
15741  }
15742  Utilities->CallLogPop(1929);
15743  return(false);
15744  }
15745  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
15746  {
15747  for(int x = 0; x < VectorCount; x++)
15748  {
15749  SearchVector.erase(SearchVector.end() - 1);
15750  }
15751  Utilities->CallLogPop(2523);
15752  return(false);
15753  }
15754  Utilities->CallLogPop(250);
15755  return(true);
15756  }
15757  else
15758  {
15759 // remove leading point with XLinkPos [1]
15760  SearchVector.erase(SearchVector.end() - 1);
15761  VectorCount--;
15762  }
15763  }
15764 // XLink set to position [SearchPos2]
15765  SearchElement.XLink = SearchElement.Link[SearchPos2];
15766  SearchElement.XLinkPos = SearchPos2;
15767  if(SearchElement.XLink == PrefDirElement1.XLink)
15768  {
15769  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15770  }
15771  else if(SearchElement.XLink == PrefDirElement2.XLink)
15772  {
15773  SearchElement = PrefDirElement2;
15774  }
15775  else // failed to find a valid exit from the point
15776  {
15777  for(int x = 0; x < VectorCount; x++)
15778  {
15779  SearchVector.erase(SearchVector.end() - 1);
15780  }
15781  Utilities->CallLogPop(251);
15782  return(false);
15783  }
15784 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15785  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15786  {
15787  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15788  {
15789  for(int x = 0; x < VectorCount; x++)
15790  {
15791  SearchVector.erase(SearchVector.end() - 1);
15792  }
15793  Utilities->CallLogPop(252);
15794  return(false);
15795  }
15796  }
15797 // push element with XLink set to position [SearchPos2]
15798  if(AutoSigsFlag)
15799  {
15800  SearchElement.AutoSignals = true;
15801  }
15802  SearchElement.PrefDirRoute = true;
15803  SearchVector.push_back(SearchElement);
15804  VectorCount++;
15805  TotalSearchCount++;
15806 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15807  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15808  AutoSigsFlag, true))
15809  {
15811  {
15813  {
15814  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15816  }
15817  for(int x = 0; x < VectorCount; x++)
15818  {
15819  SearchVector.erase(SearchVector.end() - 1);
15820  }
15821  Utilities->CallLogPop(1930);
15822  return(false);
15823  }
15824  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
15825  {
15826  for(int x = 0; x < VectorCount; x++)
15827  {
15828  SearchVector.erase(SearchVector.end() - 1);
15829  }
15830  Utilities->CallLogPop(2524);
15831  return(false);
15832  }
15833  Utilities->CallLogPop(1592);
15834  return(true);
15835  }
15836  else
15837  {
15838  for(int x = 0; x < VectorCount; x++)
15839  {
15840  SearchVector.erase(SearchVector.end() - 1);
15841  }
15842  Utilities->CallLogPop(253);
15843  return(false);
15844  }
15845  } // if leading point
15846 
15847 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15848  SearchElement = PrefDirElement1;
15849  if(AutoSigsFlag)
15850  {
15851  SearchElement.AutoSignals = true;
15852  }
15853  SearchElement.PrefDirRoute = true;
15854  SearchVector.push_back(SearchElement);
15855  VectorCount++;
15856  TotalSearchCount++;
15857  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15858  PrefDirElement = SearchElement;
15859  } // while(true)
15860 }
15861 
15862 // ---------------------------------------------------------------------------
15863 
15864 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15865 {
15866 /*
15867  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15868  and the new or extended route created from that. Hence action varies depending on whether
15869  it is a completely new route, or an extension of an existing route at the beginning or the end.
15870  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15871  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15872 
15873  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15874  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15875  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15876  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15877  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15878  is decremented;
15879  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15880  from the existing route, then enter the new route into the AllRoutesVector;
15881  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15882  then enter the new route into the AllRoutesVector.
15883 
15884  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15885  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15886  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15887  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15888  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15889  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15890  for the new route and return;
15891  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15892  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15893 
15894  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15895  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15896  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15897 
15898 */
15899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15900  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15901  if(SearchVector.size() < 1)
15902  {
15903  Utilities->CallLogPop(254);
15904  return;
15905  }
15907  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15908  {
15909  Utilities->CallLogPop(255);
15910  return;
15911  }
15912  TAllRoutes::TLockedRouteClass LockedRouteObject;
15913 
15915  unsigned int TruncatePrefDirPosition = 0;
15916 
15917  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15918 /* if have ReqPosRouteID:
15919  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15920  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15921  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15922  the existing route, then enter the new route into the AllRoutesVector
15923  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15924  then enter the new route into the AllRoutesVector
15925 */
15926  {
15929  {
15930  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15931  x++) // start at 1 as first element already in SearchVector
15932  {
15934  }
15935  // note that route numbers in map adjusted when ReqPos route cleared
15937  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15938  // set during ClearRouteDuringRouteBuildingAt
15940  {
15943  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15944  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15945  }
15946  }
15948  {
15950  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15951  }
15953  {
15954  SearchVector.pop_back();
15955  }
15956  }
15957  if(StartSelectionRouteID > -1)
15958 /* if have StartSelectionRouteID:
15959  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15960  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15961  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15962  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15963  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15964 */
15965  {
15967  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15968  {
15971  {
15972  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15973  for(unsigned int x = 0; x < SearchVector.size(); x++)
15974  {
15976  RouteNumber, GetFixedSearchElementAt(3, x));
15977  // find & store locked route truncate position in PrefDirVector for later use
15979  {
15980  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15981  {
15982  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15983  }
15984  }
15985  }
15987  {
15988  throw Exception("Error - failed to validate extended route for preferred route");
15989  }
15992  if(!AutoSigsFlag)
15993  {
15994  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15995  }
15996  // now add the reinstated locked route if required and set signals accordingly
15998  {
15999  LockedRouteObject.RouteNumber = RouteNumber;
16000  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16001  // now reset the signals for the locked route
16002  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16003  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16004  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16005  {
16006  // return all signals to red in route section to be truncated
16007  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16008  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16009  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16010  {
16011  TrackElement.Attribute = 0;
16012  Track->PlotSignal(10, TrackElement, Display);
16013  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16014  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16015  }
16016  }
16017  }
16018  AllRoutes->CheckMapAndRoutes(1); // test
16019  Utilities->CallLogPop(256);
16020  return;
16021  }
16023  {
16026  RouteElement.AutoSignals = true;
16027  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16028  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16029  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16030  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16031  }
16032  }
16033  else
16034  {
16036  }
16037 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16038 // AllRoutesVector hence nothing to do here
16039  }
16040  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16041  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16042  {
16043  throw Exception("Error - failed to validate single route for preferred route");
16044  }
16045  AllRoutes->StoreOneRoute(1, this);
16046  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16047  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16048  if(!AutoSigsFlag)
16049  {
16050  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16051  }
16052  AllRoutes->CheckMapAndRoutes(2); // test
16053  Utilities->CallLogPop(257);
16054 }
16055 
16056 // ---------------------------------------------------------------------------
16057 
16058 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16059 {
16060 /*
16061  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16062  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16063  & ensure signal/buffers/continuation.
16064  Note that can't select ConsecSignalsRoute for non-preferred routes.
16065  Check if train on element & disallow.
16066  Set default values for retained parameters:-
16067  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16068  StartSelectionRouteID = route that selection starts in if there is one;
16069 
16070  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16071  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16072  validity. This is just for safety reasons, the PrefDir values aren't used.
16073  StartElement1 & 2 are set to these PrefDirelements.
16074 
16075  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16076 
16077  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16078  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16079  blank StartElement2 (only want to use the route element), then return true.
16080  Check if adjacent to start or end of an existing route & disallow if so.
16081  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16082  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16083  SetRemainingSearchVectorValues().
16084  Finally add the required element to the SearchVector & return true.
16085 
16086 */
16087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16088  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16089  ClearRoute();
16090  int TrackVectorPosition;
16091  TTrackElement TrackElement;
16092  TPrefDirElement FirstElement, LastElement;
16093 
16094  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16095  {
16096  Utilities->CallLogPop(258);
16097  return(false);
16098  }
16099  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16100  {
16101  if(!Callon)
16102  {
16103  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16104  }
16105 // makes later adjacent route checks too complicated
16106  Utilities->CallLogPop(259);
16107  return(false);
16108  }
16109  if(Track->IsLCAtHV(21, HLoc, VLoc))
16110  {
16111  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16112  Utilities->CallLogPop(1910);
16113  return(false);
16114  }
16115 // check if selected a train & disallow if so
16116  if(TrackElement.TrainIDOnElement > -1)
16117  {
16118  if(!Callon)
16119  {
16120  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16121  }
16122  Utilities->CallLogPop(260);
16123  return(false);
16124  }
16125 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16126  TPrefDirElement PrefDirElement;
16127  int LockedVectorNumber;
16128 
16129  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16130  {
16131  if(!Callon)
16132  {
16133  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16134  }
16135  Utilities->CallLogPop(261);
16136  return(false);
16137  }
16138  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16139  {
16140  if(!Callon)
16141  {
16142  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16143  }
16144  Utilities->CallLogPop(262);
16145  return(false);
16146  }
16148 // AdjacentStartRouteNumber = -1;
16149  StartRoutePosition = TrackVectorPosition;
16150 // StartRouteSelectPosition = TrackVectorPosition;
16151 
16152  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16153  TPrefDirElement PrefDirElement2(TrackElement);
16154 
16155  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16156  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16157  TPrefDirElement BlankElement;
16158 
16159  PrefDirElement1.ELinkPos = 0;
16160  PrefDirElement1.XLinkPos = 1;
16161  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16162  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16163  if(!(PrefDirElement1.EntryExitNumber()))
16164  {
16165  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16166  // no need for bridge check as bridge selections not allowed
16167  }
16168  PrefDirElement1.CheckCount = 9;
16169  PrefDirElement2.ELinkPos = 1;
16170  PrefDirElement2.XLinkPos = 0;
16171  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16172  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16173  if(!(PrefDirElement2.EntryExitNumber()))
16174  {
16175  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16176  }
16177  PrefDirElement2.CheckCount = 9; // both now set
16178 
16179 // set StartElements to the above PrefDirElements
16180  StartElement1 = PrefDirElement1;
16181  StartElement2 = PrefDirElement2;
16182 
16183 // no PrefDir check needed as doesn't need to be in a PrefDir
16184 
16185 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16187  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16188 
16189  if(RoutePair.first > -1)
16190  {
16191  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16192  {
16193  if(!Callon)
16194  {
16195  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16196  }
16197  Utilities->CallLogPop(263);
16198  return(false);
16199  }
16200  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16201  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16202  {
16203  if(!Callon)
16204  {
16205  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16206  }
16207  Utilities->CallLogPop(264);
16208  return(false);
16209  }
16210  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16211  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16212  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16213  {
16214  if(!Callon)
16215  {
16216  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16217  }
16218  Utilities->CallLogPop(265);
16219  return(false);
16220  }
16221  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16223  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16224  StartElement2 = BlankElement; // only use the route element
16226  Utilities->CallLogPop(266);
16227  return(true); // all retained values set
16228  }
16229 
16230  else // selection not in an existing route
16231  {
16232 // check if it's adjacent to start of an an existing route,
16233  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16234  {
16235  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16236  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16237  {
16238  if(!Callon)
16239  {
16240  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16241  }
16242  Utilities->CallLogPop(267);
16243  return(false);
16244  }
16245  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16246  {
16247  if(!Callon)
16248  {
16249  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16250  }
16251  Utilities->CallLogPop(268);
16252  return(false);
16253  }
16254  }
16255 // check if it's adjacent to end of an an existing route,
16256  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16257  {
16259  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16260  {
16261  if(!Callon)
16262  {
16263  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16264  }
16265  Utilities->CallLogPop(269);
16266  return(false);
16267  }
16268  }
16269  // not in a route or adjacent to start or end of a route
16270  // in this case reset all variable values to -1 & CheckCount to 4
16271  StartElement1.ELink = -1;
16272  StartElement1.ELinkPos = -1;
16273  StartElement1.XLink = -1;
16274  StartElement1.XLinkPos = -1;
16275  StartElement1.EXNumber = -1;
16276  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16277  StartElement2 = BlankElement;
16278  SearchVector.push_back(StartElement1);
16279  Utilities->CallLogPop(270);
16280  return(true);
16281  }
16282 }
16283 
16284 // ---------------------------------------------------------------------------
16285 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16286 
16287 /*
16288  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16289 
16290  Declare the following integers:-
16291  EndPosition - TrackVectorPosition for the selection;
16292  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16293  Check if selection is a valid track element and set EndPosition.
16294  Cancel if select original start element, then check that not points, bridge or crossover.
16295  Check & fail if a train is present at the selection.
16296  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16297  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16298  No check needed for selection in EveryPrefDir.
16299  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16300  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16301  as don't need it if in a route.
16302  Check if selection adj to start or end of a route and disallow.
16303  Fail if select same route as starting route, though should already have failed earlier if this is so.
16304 
16305  If there's a StartSelectionRouteID then StartElement1 will be set to
16306  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16307  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16308  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16309  to add the new route to the AllRoutesVectorPtr.
16310  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16311  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16312  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16313  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16314  the search vector values and return.
16315  If not returned yet then have failed to find the required element so return false with no message.
16316 
16317 */
16318 
16319 {
16320 // get EndPosition
16321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16322  AnsiString(VLoc));
16323  int EndPosition;
16324  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16325 
16326  TotalSearchCount = 0;
16327  ReqPosRouteID = IDInt(-1); // for not used
16328  TTrackElement TrackElement;
16329  TPrefDirElement BlankElement;
16331 
16332  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16333  {
16334  Utilities->CallLogPop(271);
16335  return(false);
16336  }
16337 // EndPosition = EndSelectPosition;
16338 // cancel selection if on original start element
16339  if(EndPosition == StartRoutePosition)
16340  {
16341  Utilities->CallLogPop(272);
16342  return(false);
16343  }
16344  if(Track->IsLCAtHV(22, HLoc, VLoc))
16345  {
16346  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16347  Utilities->CallLogPop(1911);
16348  return(false);
16349  }
16350  if((TrackElement.TrackType == Points) && !Callon)
16351  {
16352  if(!Callon)
16353  {
16354  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16355  }
16356 // makes later adjacent route checks too complicated
16357  Utilities->CallLogPop(273);
16358  return(false);
16359  }
16360  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16361  {
16362  if(!Callon)
16363  {
16364  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16365  }
16366 // makes later adjacent route checks too complicated
16367  Utilities->CallLogPop(1861);
16368  return(false);
16369  }
16370 // check if train on element
16371  if(TrackElement.TrainIDOnElement > -1)
16372  {
16373  if(!Callon)
16374  {
16375  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
16376  }
16377  Utilities->CallLogPop(274);
16378  return(false);
16379  }
16380 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
16381 // check passed)
16382  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16383  TPrefDirElement EndElement2(TrackElement);
16384 
16385  EndElement1.TrackVectorPosition = EndPosition;
16386  EndElement2.TrackVectorPosition = EndPosition;
16387  EndElement1.ELinkPos = 0;
16388  EndElement1.XLinkPos = 1;
16389  EndElement1.ELink = EndElement1.Link[0];
16390  EndElement1.XLink = EndElement1.Link[1];
16391  if(!(EndElement1.EntryExitNumber()))
16392  {
16393  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
16394  }
16395  EndElement1.CheckCount = 9;
16396  EndElement2.ELinkPos = 1;
16397  EndElement2.XLinkPos = 0;
16398  EndElement2.ELink = EndElement2.Link[1];
16399  EndElement2.XLink = EndElement2.Link[0];
16400  if(!(EndElement2.EntryExitNumber()))
16401  {
16402  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
16403  }
16404  EndElement2.CheckCount = 9; // both now set
16405 
16406 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
16407 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
16408 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
16409 
16410  if(EndElement1.HLoc >= StartElement1.HLoc)
16411  {
16413  SearchLimitHighH = EndElement1.HLoc + 15;
16414  }
16415  else
16416  {
16417  SearchLimitLowH = EndElement1.HLoc - 15;
16419  }
16420  if(EndElement1.VLoc >= StartElement1.VLoc)
16421  {
16423  SearchLimitHighV = EndElement1.VLoc + 15;
16424  }
16425  else
16426  {
16427  SearchLimitLowV = EndElement1.VLoc - 15;
16429  }
16430 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
16431  check & TotalSearchCounts check
16432  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
16433  {
16434  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
16435  Utilities->CallLogPop(1694);
16436  return false;
16437  }
16438 */
16439 // don't need EveryPrefDir check for NonPreferredRoute
16440 
16441 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
16442 // bool InRoute = false;
16444  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16445 
16446  if(RoutePair.first > -1)
16447  {
16448  if(RoutePair.second != 0) // not first element in existing route so no good
16449  {
16450  if(!Callon)
16451  {
16452  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
16453  }
16454  Utilities->CallLogPop(275);
16455  return(false);
16456  }
16457  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
16458 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
16459  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
16460  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
16461  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16462  {
16463  if(!Callon)
16464  {
16465  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
16466  }
16467  Utilities->CallLogPop(276);
16468  return(false);
16469  }
16470  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16471  EndElement2 = BlankElement; // only need the route element
16472  EndPosition = EndElement1.TrackVectorPosition;
16473  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16474  }
16475 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16476  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16477  {
16478  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16479  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16480 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16481 // && (AdjPosition != StartRoutePosition))
16482  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16483  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16484  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16485  {
16486  if(!Callon)
16487  {
16488  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16489  }
16490  Utilities->CallLogPop(277);
16491  return(false);
16492  }
16493 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16494 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16495  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16496  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16497  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16498  (AdjPosition != StartRoutePosition))
16499  {
16500  if(!Callon)
16501  {
16502  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16503  }
16504  Utilities->CallLogPop(278);
16505  return(false);
16506  }
16507 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16509  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16510  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16511  {
16512  if(!Callon)
16513  {
16514  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16515  }
16516  Utilities->CallLogPop(279);
16517  return(false);
16518  }
16519  }
16520 
16521 // check for same route as start element
16523  {
16524  if(!Callon)
16525  {
16526  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16527  }
16528  Utilities->CallLogPop(280);
16529  return(false);
16530  }
16531 // check for a looping route
16532  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16533  {
16535  {
16536  if(!Callon)
16537  {
16538  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16539  }
16540  Utilities->CallLogPop(1845);
16541  return(false);
16542  }
16543  }
16544 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16545 // so search from this element.
16546 
16547  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16548 
16549  if(StartSelectionRouteID > -1)
16550  {
16551  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
16552  {
16554  if(PointsToBeChanged(0, NewFailedPointsTVPos))
16555  {
16556  if(NewFailedPointsTVPos > -1)
16557  {
16558  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
16559  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
16560  " failed during route setting.");
16561  Utilities->CallLogPop(2504);
16562  return(false);
16563  }
16564  PointsChanged = true;
16565  }
16566  Utilities->CallLogPop(281);
16567  return(true);
16568  }
16569  else
16570  {
16571  if(!Callon && !Track->SuppressRouteFailMessage)
16572  {
16574  }
16575  Utilities->CallLogPop(282);
16576  return(false);
16577  }
16578  }
16579  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16580  // search on the 2 ways out of the element, which has to be a 2-ended element
16581  {
16582 // check if selection adjacent to start element and if so use that
16583  if(SearchVector.at(0).Conn[0] == EndPosition)
16584  {
16585  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
16586  {
16588  if(PointsToBeChanged(1, NewFailedPointsTVPos))
16589  {
16590  if(NewFailedPointsTVPos > -1)
16591  {
16592  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
16593  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
16594  " failed during route setting.");
16595  Utilities->CallLogPop(2506);
16596  return(false);
16597  }
16598  PointsChanged = true;
16599  }
16600  Utilities->CallLogPop(283);
16601  return(true);
16602  }
16603  else
16604  {
16605  if(!Callon && !Track->SuppressRouteFailMessage)
16606  {
16608  }
16609  Utilities->CallLogPop(284);
16610  return(false);
16611  }
16612  }
16613  else if(SearchVector.at(0).Conn[1] == EndPosition)
16614  {
16615  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
16616  {
16618  if(PointsToBeChanged(2, NewFailedPointsTVPos))
16619  {
16620  if(NewFailedPointsTVPos > -1)
16621  {
16622  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
16623  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
16624  " failed during route setting.");
16625  Utilities->CallLogPop(2508);
16626  return(false);
16627  }
16628  PointsChanged = true;
16629  }
16630  Utilities->CallLogPop(285);
16631  return(true);
16632  }
16633  else
16634  {
16635  if(!Callon && !Track->SuppressRouteFailMessage)
16636  {
16638  }
16639  Utilities->CallLogPop(286);
16640  return(false);
16641  }
16642  }
16643  // now start off in the best direction
16644  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16645 
16646  if(SearchVector.at(0).Config[BestPos] != End)
16647  {
16648  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16649  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
16650  {
16652  if(PointsToBeChanged(3, NewFailedPointsTVPos))
16653  {
16654  if(NewFailedPointsTVPos > -1)
16655  {
16656  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
16657  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
16658  " failed during route setting.");
16659  Utilities->CallLogPop(2510);
16660  return(false);
16661  }
16662  PointsChanged = true;
16663  }
16664  Utilities->CallLogPop(287);
16665  return(true);
16666  }
16667  }
16668  if(SearchVector.at(0).Config[1 - BestPos] != End)
16669  {
16670  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16671  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
16672  {
16674  if(PointsToBeChanged(4, NewFailedPointsTVPos))
16675  {
16676  if(NewFailedPointsTVPos > -1)
16677  {
16678  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
16679  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
16680  " failed during route setting.");
16681  Utilities->CallLogPop(2512);
16682  return(false);
16683  }
16684  PointsChanged = true;
16685  }
16686  Utilities->CallLogPop(288);
16687  return(true);
16688  }
16689  }
16690  }
16691  if(!Callon && !Track->SuppressRouteFailMessage)
16692  {
16694  }
16695  Utilities->CallLogPop(289);
16696  return(false);
16697 }
16698 
16699 // ---------------------------------------------------------------------------
16700 
16701 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
16702 /*
16703  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16704  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16705  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16706  Keep a count of entries in SearchVector during the current function call, so that this number can be
16707  erased for an unproductive branch search.
16708  First check (within the loop) whether XLink leads to an End & return false if so.
16709  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16710  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16711  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16712  train on element (unless a bridge & train on different track), or if element
16713  fouls an existing diagonal route (except if element is a leading point - these checked later).
16714  Then check if found required element. If so save it & return true.
16715  If not the required element check if buffer or continuation, & if so erase all searchvector
16716  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16717  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16718  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16719  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16720  When return true have 8 items from CheckCount established, only waiting for EXNumber
16721 */
16722 {
16723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16724  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16725  int VectorCount = 0;
16726 
16727 // check for a fouled diagonal for first element. Added for v1.3.2
16728  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16729  (CurrentTrackElement.Link[XLinkPos] == 9))
16730  {
16731  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16732  {
16733  for(int x = 0; x < VectorCount; x++)
16734  {
16735  SearchVector.erase(SearchVector.end() - 1);
16736  }
16737  Utilities->CallLogPop(2044);
16738  return(false);
16739  }
16740  }
16741  while(true)
16742  {
16743  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16744  {
16745  for(int x = 0; x < VectorCount; x++)
16746  {
16747  SearchVector.erase(SearchVector.end() - 1);
16748  }
16749  Utilities->CallLogPop(1927);
16750  return(false);
16751  }
16752  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16753  {
16754  for(int x = 0; x < VectorCount; x++)
16755  {
16756  SearchVector.erase(SearchVector.end() - 1);
16757  }
16758  Utilities->CallLogPop(290);
16759  return(false);
16760  }
16761  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16762  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16763  TPrefDirElement SearchElement(NextTrackElement);
16764  SearchElement.TrackVectorPosition = NextPosition;
16765  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16766  SearchElement.ELinkPos = NextELinkPos;
16767  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16768  int NextXLinkPos;
16769  if(SearchElement.ELinkPos == 0)
16770  {
16771  NextXLinkPos = 1;
16772  }
16773  if(SearchElement.ELinkPos == 1)
16774  {
16775  NextXLinkPos = 0;
16776  }
16777  if(SearchElement.ELinkPos == 2)
16778  {
16779  NextXLinkPos = 3;
16780  }
16781  if(SearchElement.ELinkPos == 3)
16782  {
16783  NextXLinkPos = 2;
16784  }
16785  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16786  {
16787  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16788  // but may be buffers, continuation or gap
16789  SearchElement.XLinkPos = NextXLinkPos;
16790  }
16791 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16792 // can't set XLink or XLinkPos yet if the element is a leading point.
16793 
16794 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16795  for(unsigned int x = 0; x < SearchVector.size(); x++)
16796  {
16797  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16798  {
16799  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16800  // OK if it's a bridge & routes on different tracks
16801  {
16802  for(int x = 0; x < VectorCount; x++)
16803  {
16804  SearchVector.erase(SearchVector.end() - 1);
16805  }
16806  Utilities->CallLogPop(291);
16807  return(false);
16808  }
16809  }
16810  }
16811 
16812 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16813  TAllRoutes::TRouteElementPair SecondPair;
16815  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16816  if(RoutePair.first > -1)
16817  {
16818  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16819  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16820  RoutePair.second).ELinkPos)))
16821  {
16822  // still OK if start of an expected route
16823  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16824  {
16825  for(int x = 0; x < VectorCount; x++)
16826  {
16827  SearchVector.erase(SearchVector.end() - 1);
16828  }
16829  Utilities->CallLogPop(292);
16830  return(false); // only allow for start of an expected route
16831  }
16832  }
16833  }
16834  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16835  {
16836  // OK if it's a bridge & routes on different tracks
16837  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16838  SecondPair.second).ELinkPos)))
16839  {
16840  // still OK if start of an expected route
16841  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16842  {
16843  for(int x = 0; x < VectorCount; x++)
16844  {
16845  SearchVector.erase(SearchVector.end() - 1);
16846  }
16847  Utilities->CallLogPop(293);
16848  return(false); // only allow for start of an expected route
16849  }
16850  }
16851  }
16852 // check if a train on element, unless a bridge & train on different track
16853 // OK of same train as start element - no, drop this
16854 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16855  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16856  {
16857  for(int x = 0; x < VectorCount; x++)
16858  {
16859  SearchVector.erase(SearchVector.end() - 1);
16860  }
16861  Utilities->CallLogPop(294);
16862  return(false);
16863  }
16864  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16865  {
16866  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16867  {
16868  for(int x = 0; x < VectorCount; x++)
16869  {
16870  SearchVector.erase(SearchVector.end() - 1);
16871  }
16872  Utilities->CallLogPop(295);
16873  return(false);
16874  }
16875  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16876  {
16877  for(int x = 0; x < VectorCount; x++)
16878  {
16879  SearchVector.erase(SearchVector.end() - 1);
16880  }
16881  Utilities->CallLogPop(296);
16882  return(false);
16883  }
16884  }
16885 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16886  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16887  {
16888  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16889  {
16890  for(int x = 0; x < VectorCount; x++)
16891  {
16892  SearchVector.erase(SearchVector.end() - 1);
16893  }
16894  Utilities->CallLogPop(297);
16895  return(false);
16896  }
16897  }
16898 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16899 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16900 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16902  {
16903  for(int x = 0; x < VectorCount; x++)
16904  {
16905  SearchVector.erase(SearchVector.end() - 1);
16906  }
16907  Utilities->CallLogPop(1689);
16908  return(false);
16909  }
16910 // check if found it
16911  if(SearchElement.TrackVectorPosition == RequiredPosition)
16912  {
16913  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16914  {
16915  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16916  {
16917  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16918  }
16919  else
16920  {
16921  SearchElement.XLinkPos = 1;
16922  }
16923 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16924  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16925  }
16926  SearchVector.push_back(SearchElement);
16927  VectorCount++; // not really needed but include for tidyness
16928  TotalSearchCount++;
16929  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
16930  {
16931  for(int x = 0; x < VectorCount; x++)
16932  {
16933  SearchVector.erase(SearchVector.end() - 1);
16934  }
16935  Utilities->CallLogPop(2525);
16936  return(false);
16937  }
16938  Utilities->CallLogPop(298);
16939  return(true);
16940  }
16941 // Not the required element - check if a buffer or continuation
16942  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16943  {
16944  for(int x = 0; x < VectorCount; x++)
16945  {
16946  SearchVector.erase(SearchVector.end() - 1);
16947  }
16948  Utilities->CallLogPop(299);
16949  return(false);
16950  }
16951 // check if SearchVector exceeds a size of 150
16952  if(SearchVector.size() > 150)
16953  {
16954  for(int x = 0; x < VectorCount; x++)
16955  {
16956  SearchVector.erase(SearchVector.end() - 1);
16957  }
16958  Utilities->CallLogPop(1421);
16959  return(false);
16960  }
16961 //deal with failed points, added at v2.13.0
16962  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
16963  {
16964  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
16965  {
16966  SearchElement.XLinkPos = 1;
16967  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16968  }
16969  else
16970  {
16971  SearchElement.XLinkPos = 3;
16972  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16973  }
16974  }
16975  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
16976  {
16977  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16978  {
16979  for(int x = 0; x < VectorCount; x++)
16980  {
16981  SearchVector.erase(SearchVector.end() - 1);
16982  }
16983  Utilities->CallLogPop(2533);
16984  return(false);
16985  }
16986  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16987  {
16988  for(int x = 0; x < VectorCount; x++)
16989  {
16990  SearchVector.erase(SearchVector.end() - 1);
16991  }
16992  Utilities->CallLogPop(2534);
16993  return(false);
16994  }
16995  }
16996 
16997 // check if reached a non-failed leading point
16998  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
16999  { //added !Failed condition at v2.13.0 to exclude failed points
17000 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17001  int SearchPos1 = SearchElement.Attribute + 1;
17002  int SearchPos2;
17003  if(SearchPos1 == 2)
17004  {
17005  SearchPos1++;
17006  }
17007  if(SearchPos1 == 1)
17008  {
17009  SearchPos2 = 3;
17010  }
17011  else
17012  {
17013  SearchPos2 = 1;
17014  }
17015 // push element with XLink set to position [SearchPos1]
17016  SearchElement.XLink = SearchElement.Link[SearchPos1];
17017  SearchElement.XLinkPos = SearchPos1;
17018 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17019  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17020  {
17021  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17022  {
17023  for(int x = 0; x < VectorCount; x++)
17024  {
17025  SearchVector.erase(SearchVector.end() - 1);
17026  }
17027  Utilities->CallLogPop(300);
17028  return(false);
17029  }
17030  }
17031  SearchVector.push_back(SearchElement);
17032  VectorCount++;
17033  TotalSearchCount++;
17034 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17035 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17036 // recursive search as has to be a TTrackElement for non-preferred route searches
17037  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17038  {
17039  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17040  {
17041  for(int x = 0; x < VectorCount; x++)
17042  {
17043  SearchVector.erase(SearchVector.end() - 1);
17044  }
17045  Utilities->CallLogPop(2526);
17046  return(false);
17047  }
17048  Utilities->CallLogPop(301);
17049  return(true);
17050  }
17051  else
17052  {
17053 // remove leading point with XLinkPos [SearchPos1]
17054  SearchVector.erase(SearchVector.end() - 1);
17055  VectorCount--;
17056 // push element with XLink set to position [SearchPos2]
17057  SearchElement.XLink = SearchElement.Link[SearchPos2];
17058  SearchElement.XLinkPos = SearchPos2;
17059 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17060  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17061  {
17062  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17063  {
17064  for(int x = 0; x < VectorCount; x++)
17065  {
17066  SearchVector.erase(SearchVector.end() - 1);
17067  }
17068  Utilities->CallLogPop(302);
17069  return(false);
17070  }
17071  }
17072  SearchVector.push_back(SearchElement);
17073  VectorCount++;
17074  TotalSearchCount++;
17075 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17076  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17077  {
17078  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17079  {
17080  for(int x = 0; x < VectorCount; x++)
17081  {
17082  SearchVector.erase(SearchVector.end() - 1);
17083  }
17084  Utilities->CallLogPop(2527);
17085  return(false);
17086  }
17087  Utilities->CallLogPop(303);
17088  return(true);
17089  }
17090  else
17091  {
17092  for(int x = 0; x < VectorCount; x++)
17093  {
17094  SearchVector.erase(SearchVector.end() - 1);
17095  }
17096  Utilities->CallLogPop(304);
17097  return(false);
17098  }
17099  }
17100  } // if leading point
17101 
17102 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17103 // ready for next element on route
17104  SearchVector.push_back(SearchElement);
17105  VectorCount++;
17106  TotalSearchCount++;
17107  CurrentTrackElement = SearchElement;
17108  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17109  } // while(true)
17110 }
17111 
17112 // ---------------------------------------------------------------------------
17113 
17115 
17116 /*
17117  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17118  having all values set (since not necessarily on PrefDirs).
17119  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17120  (if it was the start), so these are checked first and set if necessary. All elements now have
17121  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17122  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17123  to set the route colour and direction graphics.
17124 */
17125 
17126 {
17127  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17128  if(SearchVector.size() == 0)
17129  {
17130  throw Exception("Error, SearchVector empty");
17131  }
17132 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17133 // hence need to examine and update it if necessary
17134  TPrefDirElement SecondElement;
17135 
17136  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17137  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17138  // need above check or SecondElement will fail
17139  {
17140  SecondElement = SearchVector.at(1);
17141  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17142  for(int x = 0; x < 4; x++)
17143  {
17144  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17145  {
17146  if(SearchVector.at(0).XLink == -1) // i.e. not set
17147  {
17148  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17149  SearchVector.at(0).XLinkPos = x;
17150  }
17151  int ELinkPos;
17152  if(SearchVector.at(0).XLinkPos == 0)
17153  {
17154  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17155  }
17156  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17157  if(SearchVector.at(0).XLinkPos == 1)
17158  {
17159  ELinkPos = 0;
17160  }
17161  if(SearchVector.at(0).XLinkPos == 2)
17162  {
17163  ELinkPos = 3;
17164  }
17165  if(SearchVector.at(0).XLinkPos == 3)
17166  {
17167  ELinkPos = 2;
17168  }
17169  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17170  {
17171  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17172  SearchVector.at(0).ELinkPos = ELinkPos;
17173  }
17174  break; // no point going any further
17175  }
17176  }
17177  }
17178  for(unsigned int x = 0; x < SearchVector.size(); x++)
17179  {
17180  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17181 // set EXNumber
17182  if(!(SearchVector.at(x).EntryExitNumber()))
17183  {
17184  throw Exception("Error in EntryExitNumber 3");
17185  }
17186  SearchVector.at(x).CheckCount++;
17187 // all values now incorporated
17188  }
17189 
17190  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17191 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17192 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17193  Utilities->CallLogPop(305);
17194 }
17195 
17196 // ---------------------------------------------------------------------------
17197 
17199 
17200 /*
17201  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17202  AutoSigsRoute.
17203  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17204  beginning or the end.
17205  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17206  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17207  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17208  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17209  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17210  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17211  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17212 
17213  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17214  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17215  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17216  route at the start.
17217 
17218  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17219  for the new route and return.
17220 */
17221 
17222 {
17223  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17224  AnsiString(ReqPosRouteID.GetInt()));
17225  if(SearchVector.size() < 1)
17226  {
17227  Utilities->CallLogPop(306);
17228  return;
17229  }
17230  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17231  if(!ValidatePrefDir(6))
17232  {
17233  Utilities->CallLogPop(307);
17234  return;
17235  }
17236  TAllRoutes::TLockedRouteClass LockedRouteObject;
17237 
17239  unsigned int TruncatePrefDirPosition = 0;
17240 
17241  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17242 /* if have ReqPosRouteID:
17243  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17244  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17245  then enter the new route into the AllRoutesVector
17246 */
17247  {
17249  {
17250  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17251  x++) // start at 1 as first element already in SearchVector
17252  {
17254  }
17255  // note that route numbers in map adjusted when ReqPos route cleared
17257  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17258  // set during ClearRouteDuringRouteBuildingAt)
17260  {
17263  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17264  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17265  }
17266  }
17268  {
17269  SearchVector.pop_back();
17270  }
17271  }
17272  if(StartSelectionRouteID > -1)
17273 /* if have StartSelectionRouteID:
17274  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17275  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17276 */
17277  {
17279  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17280  {
17282  {
17283  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17284  for(unsigned int x = 0; x < SearchVector.size(); x++)
17285  {
17287  RouteNumber, GetFixedSearchElementAt(7, x));
17288  // find & store locked route truncate position in PrefDirVector for later use
17290  {
17291  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
17292  {
17293  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17294  }
17295  }
17296  }
17298  {
17299  throw Exception("Failed to validate extended route for nonpreferred route");
17300  }
17303  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17304  // now add the reinstated locked route if required and set signals accordingly
17305  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17306  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17307  // that I haven't thought of
17309  {
17310  LockedRouteObject.RouteNumber = RouteNumber;
17311  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17312  // now reset the signals for the locked route
17313  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17314  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17315  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17316  {
17317  // return all signals to red in route section to be truncated
17318  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17319  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17320  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17321  {
17322  TrackElement.Attribute = 0;
17323  Track->PlotSignal(11, TrackElement, Display);
17324  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17325  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17326  }
17327  }
17328  }
17329  AllRoutes->CheckMapAndRoutes(3); // test
17330  Utilities->CallLogPop(308);
17331  return;
17332  }
17333  }
17334  else
17335  {
17337  }
17338 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17339 // hence nothing to do here
17340  }
17341  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17342  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17343  {
17344  throw Exception("Failed to validate single route for nonpreferred route");
17345  }
17346  AllRoutes->StoreOneRoute(2, this);
17347  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
17348  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
17349  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
17350  AllRoutes->CheckMapAndRoutes(4); // test
17351  Utilities->CallLogPop(309);
17352 }
17353 
17354 // ---------------------------------------------------------------------------
17355 
17356 void TOneRoute::SetRoutePoints(int Caller) const
17357 /*
17358  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
17359  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
17360  when they were created.
17361 */
17362 {
17363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
17364  if(!PrefDirVector.empty())
17365  {
17366  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17367  {
17368  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
17369  {
17370  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
17371  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
17372  }
17373  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
17374  {
17375  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
17376  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
17377  }
17378  }
17379  }
17380  Utilities->CallLogPop(327);
17381 }
17382 
17383 // ---------------------------------------------------------------------------
17384 
17385 void TOneRoute::SetRouteSignals(int Caller) const
17386 /* Used for new train additions in AddTrain and in route setting
17387  Set the signals as follows:-
17388  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
17389  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
17390  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
17391  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
17392  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
17393  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
17394  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
17395  of the foregoing are found but there is a further forward linked forward route then the function returns false with
17396  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
17397 
17398  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
17399  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
17400  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
17401  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
17402  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
17403  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
17404  as a green signal.
17405 */
17406 {
17407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
17408  if(!PrefDirVector.empty())
17409  {
17410  // get target Attribute value, check first if there is a forward linked route
17411  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
17412  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
17413  int ForwardLinkedRouteNumber, Attribute = 0;
17414  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17415  // Note that LastElement can't be points but can be linked to points
17416  {
17417  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
17418  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17419  {
17420  if(ForwardLinkedRouteNumber > -1)
17421  {
17422  int NextForwardLinkedRouteNumber = -1;
17423  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
17424  Attribute)))
17425  {
17426  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
17427  }
17428  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
17429  // Attribute = 3, else if find signal (other than a ground signal with Attribute > 0 [added at v2.14.0]) then Attribute = (signal attribute + 1) (or
17430  // same as signal Attribute if ground signal with Attribute > 0) up to a max value of 3. All these return true, if find a forward linked
17431  // route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
17432  }
17433  }
17434  }
17435  int RouteNumber;
17436  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
17437  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
17438  if(RouteType != TAllRoutes::NoRoute)
17439  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
17440  {
17441  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
17442  }
17443  }
17444  Utilities->CallLogPop(1720);
17445 }
17446 
17447 // ---------------------------------------------------------------------------
17448 
17449 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
17450 {
17451  //true if at any point in SearchVector points have to be changed,
17452  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
17453  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
17454  NewFailedPointsTVPos = -1; //default value for no new failure
17455  bool PointsChanged = false;
17456  if(!SearchVector.empty())
17457  {
17458  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
17459  {
17460  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
17461  //check for an existing failed point where needs to change to make the route
17462  int Attr = TE.Attribute;
17463  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
17464  {
17465  if(Attr == 1) //currently set to diverge
17466  {
17467  //here add new failure possibility at v2.13.0
17468  if(Utilities->FailureMode != FNil)
17469  {
17470  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17471  {
17473  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17474  IFE.TVPos = NewFailedPointsTVPos;
17475  TE.Failed = true;
17476  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17478  TE.SpeedLimit01 = 10; //values while failed
17479  TE.SpeedLimit23 = 10;
17480  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17481  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17482  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17483  //set repair time, random value in minutes between 10 and 179
17484  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
17485  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17486  IFE.RepairTime = RepairTime;
17488  Track->FailedPointsVector.push_back(IFE);
17489  Utilities->CallLogPop(1717);
17490  return(true); //return so only allow one failure per route
17491  }
17492  }
17493  PointsChanged = true; //this is used for setting the flash time
17494  }
17495  }
17496  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
17497  {
17498  if(Attr == 0) //currently set to go straight
17499  {
17500  //here add failure possibility at v2.13.0
17501  if(Utilities->FailureMode != FNil)
17502  {
17503  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17504  {
17506  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17507  IFE.TVPos = NewFailedPointsTVPos;
17508  TE.Failed= true;
17509  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17511  TE.SpeedLimit01 = 10; //values while failed
17512  TE.SpeedLimit23 = 10;
17513  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17514  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17515  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17516  //set repair time, random value in minutes between 10 and 179
17517  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
17518  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17519  IFE.RepairTime = RepairTime;
17521  Track->FailedPointsVector.push_back(IFE);
17522  Utilities->CallLogPop(1718);
17523  return(true); //only allow one failure per route
17524  }
17525  }
17526  PointsChanged = true;
17527  }
17528  }
17529  }
17530  }
17531  Utilities->CallLogPop(1719);
17532  return(PointsChanged);
17533 }
17534 
17535 // ---------------------------------------------------------------------------
17536 
17537 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
17538 /*
17539  Works forward through the route until finds:-
17540  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17541  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
17542  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
17543  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17544  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
17545  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17546  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17547  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17548  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
17549 */
17550 {
17551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
17552  Attribute = 0;
17553  NextForwardLinkedRouteNumber = -1;
17554  for(unsigned int x = 0; x < PrefDirSize(); x++)
17555  {
17556  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
17557  if(PrefDirVector.at(x).TrackType == Bridge)
17558  {
17559  if(PrefDirVector.at(x).XLinkPos < 2)
17560  {
17561  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17562  }
17563  else
17564  {
17565  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17566  }
17567  }
17568  if(TrainID != -1)
17569  {
17570  Utilities->CallLogPop(328);
17571  return(true);
17572  }
17573  if(PrefDirVector.at(x).TrackType == Buffers)
17574  {
17575  Attribute = 1;
17576  Utilities->CallLogPop(329);
17577  return(true);
17578  }
17579  if(PrefDirVector.at(x).TrackType == Continuation)
17580  {
17581  Attribute = 3;
17582  Utilities->CallLogPop(330);
17583  return(true);
17584  }
17585  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17586  {
17587  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17588  {
17589  Attribute = 0;
17590  Utilities->CallLogPop(1950);
17591  return(true);
17592  }
17593  }
17594  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
17595  {
17596  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
17597  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
17598  {
17599  Attribute++;
17600  }
17601  if(Attribute > 3)
17602  {
17603  Attribute = 3;
17604  }
17605  Utilities->CallLogPop(331);
17606  return(true);
17607  }
17608  if(x == PrefDirSize() - 1)
17609  {
17610  TPrefDirElement LastElement = PrefDirVector.at(x);
17611  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17612  {
17613  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
17614  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17615  {
17616  Attribute = 0;
17617  Utilities->CallLogPop(332);
17618  return(false);
17619  }
17620  }
17621  }
17622  }
17623  Utilities->CallLogPop(333);
17624  return(true);
17625 }
17626 
17627 // ---------------------------------------------------------------------------
17628 
17629 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
17630 /*
17631  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17632 
17633  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17634  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17635  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17636  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17637  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17638  a route.
17639 
17640  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17641  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17642  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
17643  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
17644  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17645  reference. If no train is found before the beginning of the route is reached the function returns true
17646 
17647  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
17648  and the next rearwards signal becomes yellow, although it's the first in the route
17649 */
17650 {
17651  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
17652  AnsiString(PrefDirVectorStartPosition));
17653  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17654  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17655 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17656 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17657  bool SkipContinuationAndBufferAttributeChange = false;
17658 
17659  if(!PrefDirVector.empty())
17660  {
17661  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17662  {
17663  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17664  if(PrefDirPtr->TrackType == Bridge)
17665  {
17666  if(PrefDirPtr->XLinkPos < 2)
17667  {
17668  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17669  }
17670  else
17671  {
17672  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17673  }
17674  }
17675  if(TrainID != -1)
17676  {
17677  SkipContinuationAndBufferAttributeChange = true;
17678  break;
17679  }
17680  }
17681 
17684  {
17685  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17686  AutoSigVectorIT++)
17687  {
17688  if(!AllRoutes->AllRoutesVector.empty())
17689  {
17690  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17691  {
17692  SkipContinuationAndBufferAttributeChange = true;
17693  break;
17694  }
17695  }
17696  }
17697  }
17699  {
17700  SkipContinuationAndBufferAttributeChange = true;
17701  }
17702  if(!SkipContinuationAndBufferAttributeChange)
17703  {
17704  if(PrefDirVector.back().TrackType == Buffers)
17705  {
17706  Attribute = 1; // treat buffer as red signal
17707  }
17708  if(PrefDirVector.back().TrackType == Continuation)
17709  {
17710  Attribute = 3; // treat continuation as a green signal
17711  }
17712  }
17713  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17714  {
17715  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17716  if(PrefDirPtr->TrackType == Bridge)
17717  {
17718  if(PrefDirPtr->XLinkPos < 2)
17719  {
17720  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17721  }
17722  else
17723  {
17724  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17725  }
17726  }
17727  if(TrainID != -1)
17728  {
17729  Utilities->CallLogPop(334);
17730  return(false);
17731  }
17732  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17733  // the attribute to 0 so first signal behind the LC is red
17734  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17735  {
17736  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17737  {
17738  Attribute = 0;
17739  }
17740  }
17741 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17742 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17743  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17744  {
17745  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17746  PrefDirPtr->PrefDirRoute)
17747  {
17748 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17749 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17750  int LockedVecNum = 0; //not used
17751  TPrefDirElement DummyPrefDir; //not used
17752  bool KeepAttributeAt0ForLockedRoute = false;
17753  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17754  LockedVecNum))
17755  {
17756  Attribute = 0;
17757  KeepAttributeAt0ForLockedRoute = true;
17758  }
17759 //end of v2.9.2 addition
17760 
17761 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
17762  bool NotGroundSignal = false;
17763  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
17764  {
17765  NotGroundSignal = true;
17766  }
17767 
17768  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
17769  {
17770  Attribute = 0; //stays at 0
17771  }
17772 
17773  if(Attribute < 3)
17774  {
17775  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17776  }
17777  else
17778  {
17779  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17780  }
17781  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17782  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17783  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17784  {
17785  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17786  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17787  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17788  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17789  }
17790  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
17791  { //if groundsignal attrib is 0 then do need to increment
17792  Attribute++; //this is for the next signal rearwards, not the current one
17793  }
17794 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
17795  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
17796  }
17797  }
17798  }
17799  }
17800  Utilities->CallLogPop(335);
17801  return(true);
17802 }
17803 
17804 // ---------------------------------------------------------------------------
17805 
17806 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17807 /*
17808  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17809  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17810  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17811  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17812  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17813  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17814  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17815  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17816 */
17817 {
17818  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17819  "," + AnsiString((short)PrefDirRoute));
17820  bool ElementInRoute = false;
17821  bool TrainOccupyingRoute = false;
17822 
17823  for(unsigned int b = 0; b < PrefDirSize(); b++)
17824  {
17825  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17826  {
17827  ElementInRoute = true;
17828  break;
17829  }
17830  }
17831  if(!ElementInRoute)
17832  {
17833  ReturnFlag = NotInRoute;
17834  Utilities->CallLogPop(336);
17835  return;
17836  }
17837 // it is in the route so continue, first look for a train or a flashing level crossing
17838  for(int b = PrefDirSize() - 1; b >= 0; b--)
17839  {
17840  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17841  if(PrefDirVector.at(b).TrackType == Bridge)
17842  {
17843  if(PrefDirVector.at(b).XLinkPos < 2)
17844  {
17845  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17846  }
17847  else
17848  {
17849  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17850  }
17851  }
17852  if(TrainID != -1)
17853  {
17854 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17855 // ReturnFlag = InRouteFalse;
17856 // Utilities->CallLogPop(337);
17857 // return;
17858 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17859  TrainOccupyingRoute = true; // train is forward of the truncate point
17860  }
17861  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17862  {
17863  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17864  ReturnFlag = InRouteFalse;
17865  Utilities->CallLogPop(1941);
17866  return;
17867  }
17868  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17869  {
17870  break; // OK found truncate element & no flashing LC in front
17871  }
17872  }
17873 
17874  for(unsigned int b = 0; b < PrefDirSize(); b++)
17875  {
17876  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17877  {
17878  if(PrefDirVector.at(b).TrackType == Bridge)
17879  {
17880  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17881  ReturnFlag = InRouteFalse;
17882  Utilities->CallLogPop(338);
17883  return;
17884  }
17885  if(b == 1)
17886  {
17887  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17888  ReturnFlag = InRouteFalse;
17889  Utilities->CallLogPop(339);
17890  return;
17891  }
17892  if(b > 0)
17893  {
17894  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17895  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17896  {
17897  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17898  {
17899  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17900  ReturnFlag = InRouteFalse;
17901  Utilities->CallLogPop(340);
17902  return;
17903  }
17904  }
17905  else
17906  {
17907  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17908  {
17909  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17910  ReturnFlag = InRouteFalse;
17911  Utilities->CallLogPop(341);
17912  return;
17913  }
17914  }
17915  }
17916  int RouteNumber;
17918 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17919 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17920 
17921 // check if part of this route already locked & disallow if so
17922  if(!(AllRoutes->LockedRouteVector.empty()))
17923  {
17925  {
17926  if(LRVIT->RouteNumber == RouteNumber)
17927  {
17928  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17929  ReturnFlag = InRouteFalse;
17930  Utilities->CallLogPop(749);
17931  return;
17932  }
17933  }
17934  }
17935  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17936  // RouteLockingRequired only checks for trains approaching
17937  {
17940  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17941  L"Warning!", MB_YESNO | MB_ICONWARNING);
17942  TrainController->BaseTime = TDateTime::CurrentDateTime();
17944  if(button == IDNO)
17945  {
17946  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17947  Utilities->CallLogPop(342);
17948  return;
17949  }
17950  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17951  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17952  TAllRoutes::TLockedRouteClass LockedRoute;
17953  bool ExistingLockedRouteModified = false;
17954  LockedRoute.RouteNumber = RouteNumber;
17955  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17956  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17957  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17958  LockedRoute.LockStartTime = TrainController->TTClockTime;
17959 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17960 // to use the new TruncateTrackVectorPosition & LockStartTime
17961  if(!AllRoutes->LockedRouteVector.empty())
17962  {
17963  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17964  LRVIT++)
17965  {
17966  if(LRVIT->RouteNumber == RouteNumber)
17967  {
17968  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17969  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17970  ExistingLockedRouteModified = true;
17971  }
17972  }
17973  }
17974  if(!ExistingLockedRouteModified)
17975  {
17976  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17977  }
17978  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17979  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17980  {
17981  // return all signals to red in route section to be truncated
17982  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17983  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17984  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17985  {
17986  TrackElement.Attribute = 0;
17987  Track->PlotSignal(2, TrackElement, Display);
17988  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17989  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17990  }
17991  }
17992 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17993  ReturnFlag = InRouteTrue;
17994  }
17995  else
17996  {
17997  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17998  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17999  {
18000  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
18001  ReturnFlag = InRouteTrue;
18002  }
18003  }
18004  AllRoutes->CheckMapAndRoutes(5); // test
18005  Utilities->CallLogPop(343);
18006  return;
18007  }
18008  }
18009  ReturnFlag = NotInRoute;
18010  Utilities->CallLogPop(344);
18011 }
18012 
18013 // ---------------------------------------------------------------------------
18015 /*
18016  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
18017  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
18018  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
18019  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
18020  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
18021  the route colours.
18022 */
18023 {
18024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
18025  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
18027  int RouteNumber;
18028  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
18029  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
18030 
18031  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
18032  {
18033  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
18034  {
18035  if(PrefDirVector.at(x).TrackType == SignalPost)
18036  {
18037  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
18038  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
18039  }
18040  }
18041  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
18042 // already set all signals to red in route so start at start of route for further rearwards signal setting
18043  }
18044  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
18045  {
18046  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
18047  }
18048  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
18049  AllRoutes->CheckMapAndRoutes(9); // test
18050  TrainController->BaseTime = TDateTime::CurrentDateTime();
18052  Utilities->CallLogPop(345);
18053  return;
18054 }
18055 
18056 // ---------------------------------------------------------------------------
18057 
18058 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18059 /*
18060  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
18061 */
18062 {
18063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
18064  AnsiString((short)PrefDirRoute));
18065  if(SearchVector.empty())
18066  {
18067  Utilities->CallLogPop(1149);
18068  return;
18069  }
18070  for(unsigned int b = 0; b < SearchVector.size(); b++)
18071  {
18074  PrefDirRoute);
18075  }
18076  Utilities->CallLogPop(346);
18077 }
18078 
18079 // ---------------------------------------------------------------------------
18080 
18081 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18082 /*
18083  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
18084  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
18085  TOneRoute.
18086 */
18087 {
18088  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
18089  AnsiString((short)PrefDirRoute));
18090  RouteFlash.RouteFlashVector.clear();
18091  TRouteFlashElement RouteFlashElement;
18092 
18093  for(unsigned int b = 0; b < SearchVector.size(); b++)
18094  {
18095  int H = GetFixedSearchElementAt(11, b).HLoc;
18096  int V = GetFixedSearchElementAt(12, b).VLoc;
18098  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
18099  RouteFlashElement.HLoc = H;
18100  RouteFlashElement.VLoc = V;
18102  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
18103  }
18104  Utilities->CallLogPop(348);
18105 }
18106 
18107 // ---------------------------------------------------------------------------
18108 
18109 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
18110 {
18111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
18112  if(!PrefDirVector.empty())
18113  {
18114  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18115  {
18116  int H = PrefDirPtr->HLoc;
18117  int V = PrefDirPtr->VLoc;
18118  // check for any LCs that are closed to trains & set the flash values and store in the vector
18119  if(Track->IsLCAtHV(39, H, V))
18120  {
18121  if(Track->IsLCBarrierUpAtHV(0, H, V))
18122  {
18123  Track->LCChangeFlag = true;
18124  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
18125  CLC.HLoc = H;
18126  CLC.VLoc = V;
18128  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
18131  if(PrefDirRoute)
18132  {
18133  CLC.TypeOfRoute = 1;
18134  }
18135  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
18136  Track->ChangingLCVector.push_back(CLC);
18137  }
18138  }
18139  }
18140  }
18141  Utilities->CallLogPop(1948);
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18147 /*
18148  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18149  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
18150  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18151  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18152 */
18153 {
18154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
18155  if(!OverlayPlotted)
18156  {
18157  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18158  {
18159  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18160  {
18161  continue;
18162  }
18163  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
18164  Display->Update();
18165  }
18166  OverlayPlotted = true;
18167  }
18168  Utilities->CallLogPop(349);
18169 }
18170 
18171 // ---------------------------------------------------------------------------
18172 
18174 /*
18175  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18176  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
18177  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18178  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18179 */
18180 {
18181  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
18182  if(OverlayPlotted)
18183  {
18184  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18185  {
18186  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18187  {
18188  continue;
18189  }
18190  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
18191  Display->Update();
18192  }
18193  OverlayPlotted = false;
18194  }
18195  Utilities->CallLogPop(350);
18196 }
18197 
18198 // ---------------------------------------------------------------------------
18199 
18200 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
18201 {
18202 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
18203 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
18204 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
18205 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
18206 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
18207 messages, and allocate a repair time similar to points)
18208 */
18209 
18210  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
18211  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
18212  {
18213  Utilities->CallLogPop(2528);
18214  return(false);
18215  }
18216  bool FirstSignalFound = false;
18217  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
18218  {
18219  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
18220 //check for a failed point where needs to change to make the route
18221 //shouldn't be any but check to be safe
18222  int Attr = TE.Attribute;
18223  if(PDVIt->TrackType == Points)
18224  {
18225  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
18226  {
18227  if(Attr == 1) //currently set to diverge
18228  {
18229  if(TE.Failed)
18230  {
18231  Utilities->CallLogPop(2529);
18232  return(false); //return without further checking
18233  }
18234  }
18235  }
18236  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
18237  {
18238  if(Attr == 0) //currently set to go straight
18239  {
18240  if(TE.Failed)
18241  {
18242  Utilities->CallLogPop(2530);
18243  return(false); //return without further checking
18244  }
18245  }
18246  }
18247  }
18248  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
18249  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
18250  //the search vector)
18251  int XLinkPosition = PDVIt->XLinkPos;
18252  if(PDVIt->XLinkPos == -1)
18253  {
18254  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
18255  {
18256  for(int x = 0; x < 4; x++)
18257  {
18258  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
18259  {
18260  XLinkPosition = x;
18261  break;
18262  }
18263  }
18264  }
18265  else
18266  {
18267  Utilities->CallLogPop(2549);
18268  return(false); //no point going any further
18269  }
18270  }
18271  if(XLinkPosition > -1) //should be by now but be safe
18272  {
18273  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18274  {
18275  FirstSignalFound = true; //the first signal doesn't change aspect
18276  continue;
18277  }
18278  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18279  {
18280 /*
18281  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
18282  {
18283  continue; //ground signals don't fail
18284  }
18285 */
18286  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
18287  {
18289  IFE.TVPos = PDVIt->TrackVectorPosition;
18290  TE.Failed = true;
18291  TE.Attribute = 0; //stop aspect
18292  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
18293  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
18294  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
18295  " failed when changing aspect.\nTrains can only pass under signaller control.");
18296  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18297  //set repair time, random value in minutes between 10 and 179
18298  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18299  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18300  IFE.RepairTime = RepairTime;
18302  Track->FailedSignalsVector.push_back(IFE);
18304  int RouteNumber; //not used
18305  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
18306  { // 0 for LinkPos ok as a signal so only one track
18307  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
18308  }
18309  Utilities->CallLogPop(2535);
18310  return(true); //return so only allow one failure per route
18311  }
18312  }
18313  }
18314  }
18315  Utilities->CallLogPop(2531);
18316  return(false);
18317 }
18318 
18319 // ---------------------------------------------------------------------------
18320 // ---------------------------------------------------------------------------
18321 
18322 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
18323 {
18324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
18325  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18326  {
18327  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
18328  }
18329  Utilities->CallLogPop(120);
18330  return(AllRoutesVector.at(At));
18331 }
18332 
18333 // ---------------------------------------------------------------------------
18334 
18336 {
18337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
18338  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18339  {
18340  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
18341  }
18342  Utilities->CallLogPop(121);
18343  return(AllRoutesVector.at(At));
18344 }
18345 
18346 // ---------------------------------------------------------------------------
18347 
18348 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
18349 /*
18350  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
18351 */
18352 {
18353  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
18354  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18355  {
18356  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
18357  }
18358  Utilities->CallLogPop(351);
18359 }
18360 
18361 // ---------------------------------------------------------------------------
18362 
18363 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
18364 {
18365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
18366  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18367  {
18368  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
18369  }
18370  Utilities->CallLogPop(1706);
18371 }
18372 
18373 // ---------------------------------------------------------------------------
18374 
18375 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
18376 /*
18377  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
18378  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
18379  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
18380  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
18381  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
18382  length (train length).
18383 */
18384 {
18385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
18386  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
18387  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18388  {
18389  TTruncateReturnType ReturnFlag;
18390  RouteTruncateFlag = true;
18391 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
18392  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
18393  RouteTruncateFlag = false;
18394  if(ReturnFlag == NotInRoute)
18395  {
18396  continue;
18397  }
18398  else if(ReturnFlag == InRouteTrue)
18399  {
18400  Utilities->CallLogPop(352);
18401  return(true);
18402  }
18403  else if(ReturnFlag == InRouteFalse)
18404  {
18405  Utilities->CallLogPop(353);
18406  return(false);
18407  }
18408  }
18409  Utilities->CallLogPop(354);
18410  return(false);
18411 }
18412 
18413 // ---------------------------------------------------------------------------
18414 
18415 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
18416 /*
18417  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
18418  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
18419 */
18420 {
18421  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
18422  AnsiString(LinkPos));
18423  if(TrackVectorPosition == -1) // allows for continuation entries & exits
18424  {
18425  Utilities->CallLogPop(355);
18426  return(false);
18427  }
18428  THVPair Route2MultiMapKeyPair;
18429 
18430  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
18431  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
18432  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18433  TRoute2MultiMapIterator Route2MultiMapIterator;
18434 
18435  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
18436  {
18437  Utilities->CallLogPop(356);
18438  return(false);
18439  }
18440  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
18441  {
18442  Utilities->CallLogPop(1422);
18443  return(true);
18444  }
18445  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18446  {
18447  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18448 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18449 // realised after writing this that can't be points as would have been covered above, but leave anyway
18450  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
18451  Route2MultiMapIterator->second.second);
18452  EntryLinkPos = PrefDirElement1.ELinkPos;
18453  ExitLinkPos = PrefDirElement1.XLinkPos;
18454  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18455  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18456  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
18457  {
18458  Utilities->CallLogPop(357);
18459  return(true);
18460  }
18461  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
18462  {
18463  Utilities->CallLogPop(358);
18464  return(true);
18465  }
18466  }
18467  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
18468  {
18469  Utilities->CallLogPop(1423);
18470  return(true);
18471  }
18472  Utilities->CallLogPop(363);
18473  return(false); // none found
18474 }
18475 
18476 // ---------------------------------------------------------------------------
18477 
18478 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
18479  Graphics::TBitmap* &EntryDirectionGraphicPtr)
18480 /*
18481  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
18482  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
18483  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
18484  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
18485  for replotting of AutoSigsRoutes.
18486 */
18487 {
18488  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
18489  AnsiString(LinkPos));
18490  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18491  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18492  if(TrackVectorPosition == -1)
18493  {
18494  Utilities->CallLogPop(364);
18495  return(NoRoute); // allows for continuation entries & exits
18496  }
18497  THVPair Route2MultiMapKeyPair;
18498 
18499  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
18500  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
18501  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18502  TRoute2MultiMapIterator Route2MultiMapIterator;
18503 
18504  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18505  {
18506  Utilities->CallLogPop(365);
18507  return(NoRoute); // none found
18508  }
18509  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18510  {
18511  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18512 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18513  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
18514  Route2MultiMapIterator->second.second);
18515  EntryLinkPos = PrefDirElement1.ELinkPos;
18516  ExitLinkPos = PrefDirElement1.XLinkPos;
18517  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18518  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18519  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
18520  {
18521  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18522  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
18523  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18524  {
18525  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18526  }
18527  if(PrefDirElement1.AutoSignals)
18528  {
18529  Utilities->CallLogPop(366);
18530  return(AutoSigsRoute);
18531  }
18532  else
18533  {
18534  Utilities->CallLogPop(367);
18535  return(NotAutoSigsRoute);
18536  }
18537  }
18538  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
18539  {
18540  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18541  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
18542  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18543  {
18544  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18545  }
18546  if(PrefDirElement1.AutoSignals)
18547  {
18548  Utilities->CallLogPop(368);
18549  return(AutoSigsRoute);
18550  }
18551  else
18552  {
18553  Utilities->CallLogPop(369);
18554  return(NotAutoSigsRoute);
18555  }
18556  }
18557  }
18558  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18559  {
18560  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18561  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18562 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18563  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
18564  EntryLinkPos = PrefDirElement2.ELinkPos;
18565  ExitLinkPos = PrefDirElement2.XLinkPos;
18566  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18567  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18568  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
18569  {
18570  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
18571  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
18572  {
18573  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
18574  }
18575  if(PrefDirElement2.AutoSignals)
18576  {
18577  Utilities->CallLogPop(370);
18578  return(AutoSigsRoute);
18579  }
18580  else
18581  {
18582  Utilities->CallLogPop(371);
18583  return(NotAutoSigsRoute);
18584  }
18585  }
18586  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
18587  {
18588  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
18589  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
18590  {
18591  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
18592  }
18593  if(PrefDirElement2.AutoSignals)
18594  {
18595  Utilities->CallLogPop(372);
18596  return(AutoSigsRoute);
18597  }
18598  else
18599  {
18600  Utilities->CallLogPop(373);
18601  return(NotAutoSigsRoute);
18602  }
18603  }
18604  ItPair.second--; // the second iterator points one past the last matching value
18605  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
18606  EntryLinkPos = PrefDirElement3.ELinkPos;
18607  ExitLinkPos = PrefDirElement3.XLinkPos;
18608  EntryLink = PrefDirElement3.Link[EntryLinkPos];
18609  ExitLink = PrefDirElement3.Link[ExitLinkPos];
18610  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
18611  {
18612  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
18613  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
18614  {
18615  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
18616  }
18617  if(PrefDirElement3.AutoSignals)
18618  {
18619  Utilities->CallLogPop(374);
18620  return(AutoSigsRoute);
18621  }
18622  else
18623  {
18624  Utilities->CallLogPop(375);
18625  return(NotAutoSigsRoute);
18626  }
18627  }
18628  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
18629  {
18630  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
18631  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
18632  {
18633  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
18634  }
18635  if(PrefDirElement3.AutoSignals)
18636  {
18637  Utilities->CallLogPop(376);
18638  return(AutoSigsRoute);
18639  }
18640  else
18641  {
18642  Utilities->CallLogPop(377);
18643  return(NotAutoSigsRoute);
18644  }
18645  }
18646  }
18647  Utilities->CallLogPop(378);
18648  return(NoRoute); // none found
18649 }
18650 
18651 // ---------------------------------------------------------------------------
18652 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
18653 /*
18654  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
18655  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
18656 */
18657 {
18658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
18659  AnsiString(LinkPos));
18660  if(TrackVectorPosition == -1)
18661  {
18662  RouteNumber = -1;
18663  Utilities->CallLogPop(379);
18664  return(NoRoute); // allows for continuation & buffer entries & exits
18665  }
18666  THVPair Route2MultiMapKeyPair;
18667 
18668  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
18669  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
18670  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18671  TRoute2MultiMapIterator Route2MultiMapIterator;
18672 
18673  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18674  {
18675  RouteNumber = -1;
18676  Utilities->CallLogPop(380);
18677  return(NoRoute); // none found
18678  }
18679  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18680  {
18681  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18682 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18683  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
18684  Route2MultiMapIterator->second.second);
18685  EntryLinkPos = PrefDirElement1.ELinkPos;
18686  ExitLinkPos = PrefDirElement1.XLinkPos;
18687  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18688  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18689  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
18690  {
18691  RouteNumber = Route2MultiMapIterator->second.first;
18692  if(PrefDirElement1.AutoSignals)
18693  {
18694  Utilities->CallLogPop(381);
18695  return(AutoSigsRoute);
18696  }
18697  else
18698  {
18699  Utilities->CallLogPop(382);
18700  return(NotAutoSigsRoute);
18701  }
18702  }
18703  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
18704  {
18705  RouteNumber = Route2MultiMapIterator->second.first;
18706  if(PrefDirElement1.AutoSignals)
18707  {
18708  Utilities->CallLogPop(383);
18709  return(AutoSigsRoute);
18710  }
18711  else
18712  {
18713  Utilities->CallLogPop(384);
18714  return(NotAutoSigsRoute);
18715  }
18716  }
18717  }
18718  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18719  {
18720  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18721  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18722 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18723  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
18724  EntryLinkPos = PrefDirElement2.ELinkPos;
18725  ExitLinkPos = PrefDirElement2.XLinkPos;
18726  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18727  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18728  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
18729  {
18730  RouteNumber = ItPair.first->second.first;
18731  if(PrefDirElement2.AutoSignals)
18732  {
18733  Utilities->CallLogPop(385);
18734  return(AutoSigsRoute);
18735  }
18736  else
18737  {
18738  Utilities->CallLogPop(386);
18739  return(NotAutoSigsRoute);
18740  }
18741  }
18742  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
18743  {
18744  RouteNumber = ItPair.first->second.first;
18745  if(PrefDirElement2.AutoSignals)
18746  {
18747  Utilities->CallLogPop(387);
18748  return(AutoSigsRoute);
18749  }
18750  else
18751  {
18752  Utilities->CallLogPop(388);
18753  return(NotAutoSigsRoute);
18754  }
18755  }
18756  ItPair.second--; // the second iterator points one past the last matching value
18757  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
18758  EntryLinkPos = PrefDirElement3.ELinkPos;
18759  ExitLinkPos = PrefDirElement3.XLinkPos;
18760  EntryLink = PrefDirElement3.Link[EntryLinkPos];
18761  ExitLink = PrefDirElement3.Link[ExitLinkPos];
18762  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
18763  {
18764  RouteNumber = ItPair.second->second.first;
18765  if(PrefDirElement3.AutoSignals)
18766  {
18767  Utilities->CallLogPop(389);
18768  return(AutoSigsRoute);
18769  }
18770  else
18771  {
18772  Utilities->CallLogPop(390);
18773  return(NotAutoSigsRoute);
18774  }
18775  }
18776  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
18777  {
18778  RouteNumber = ItPair.second->second.first;
18779  if(PrefDirElement3.AutoSignals)
18780  {
18781  Utilities->CallLogPop(391);
18782  return(AutoSigsRoute);
18783  }
18784  else
18785  {
18786  Utilities->CallLogPop(392);
18787  return(NotAutoSigsRoute);
18788  }
18789  }
18790  }
18791  RouteNumber = -1;
18792  Utilities->CallLogPop(393);
18793  return(NoRoute); // none found
18794 }
18795 
18796 // ---------------------------------------------------------------------------
18797 
18798 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
18799 /*
18800  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
18801  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
18802  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
18803  and Route2MultiMap.
18804 */
18805 {
18806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
18807  TOneRoute EmptyRoute;
18808 
18809  EmptyRoute.RouteID = NextRouteID;
18810  NextRouteID++;
18811 
18812  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18813  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18814  {
18815  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
18816  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
18817  }
18818  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
18819  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
18820 
18821  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
18822  Utilities->CallLogPop(394);
18823 }
18824 
18825 // ---------------------------------------------------------------------------
18826 
18828 /*
18829  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
18830  that is already in Route is used.
18831 */
18832 {
18833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
18834  TOneRoute EmptyRoute;
18835 
18836  EmptyRoute.RouteID = Route->RouteID;
18837 
18838  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18839  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18840  {
18841  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
18842  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
18843  }
18844  Utilities->CallLogPop(1579);
18845 }
18846 
18847 // ---------------------------------------------------------------------------
18848 
18849 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
18850 /*
18851  When attaching a new route section to an existing route, it is sometimes necessary to erase the
18852  original route and create a new composite route. This function Erases all elements in the route
18853  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
18854  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
18855  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
18856  that are greater than the route number that is removed. The LockedRouteVector as also searched
18857  and if any relate to the route that has been cleared they are erased too, but the fact that one
18858  has been found is recorded so that it can be re-established later.
18859 */
18860 {
18861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
18862  THVPair Route2MultiMapKeyPair;
18863  TRoute2MultiMapEntry Route2MultiMapEntry;
18864  TRoute2MultiMapIterator Route2MultiMapIterator;
18865 
18866 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18867 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18868 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18869 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18870 // If so the locked route is removed from the locked vector and is lost.
18871  LockedRouteTruncateTrackVectorPosition = 0;
18872  LockedRouteLastTrackVectorPosition = 0;
18873  LockedRouteLastXLinkPos = 0;
18874  LockedRouteLockStartTime = TDateTime(0);
18875  if(!LockedRouteVector.empty())
18876  {
18877  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18878  {
18879  if(LRVIT->RouteNumber == RouteNumber)
18880  {
18881  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18882  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18883  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18884  LockedRouteLockStartTime = LRVIT->LockStartTime;
18885  LockedRouteFoundDuringRouteBuilding = true;
18886  LockedRouteVector.erase(LRVIT);
18887  }
18888  }
18889  }
18890  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18891  {
18892  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18893  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18894  }
18895  Utilities->CallLogPop(395);
18896 }
18897 
18898 // ---------------------------------------------------------------------------
18899 
18901  TRoute2MultiMapIterator &Route2MultiMapIterator)
18902 /*
18903  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18904  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18905  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18906  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18907  are given for failure.
18908 */
18909 {
18910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18911  AnsiString(VLoc) + "," + AnsiString(ELink));
18912  TRouteElementPair ReturnPair;
18913 
18914  ReturnPair.first = -1;
18915  ReturnPair.second = 0;
18916  THVPair Route2MultiMapKeyPair;
18917 
18918  Route2MultiMapKeyPair.first = HLoc;
18919  Route2MultiMapKeyPair.second = VLoc;
18920  TRoute2MultiMapEntry Route2MultiMapEntry;
18921 
18922  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18923  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18924 
18925  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18926  Route2MultiMapIterator = ItPair.first;
18927 
18928  if(ItPair.first == ItPair.second)
18929  {
18930  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18931  }
18932  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18933  {
18934  ReturnPair.first = ItPair.first->second.first;
18935  ReturnPair.second = ItPair.first->second.second;
18936  Route2MultiMapIterator = ItPair.first;
18937  Utilities->CallLogPop(396);
18938  return(ReturnPair);
18939  }
18940  ItPair.first++;
18941  if(ItPair.first == ItPair.second)
18942  {
18943  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18944  }
18945  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18946  {
18947  ReturnPair.first = ItPair.first->second.first;
18948  ReturnPair.second = ItPair.first->second.second;
18949  Route2MultiMapIterator = ItPair.first;
18950  Utilities->CallLogPop(397);
18951  return(ReturnPair);
18952  }
18953  Utilities->CallLogPop(398);
18954  return(ReturnPair);
18955 }
18956 
18957 // ---------------------------------------------------------------------------
18958 
18959 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18960 /*
18961  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18962  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18963  RouteNumber (route position in AllRoutes vector is returned as a reference.
18964  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18965  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18966 */
18967 {
18968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18969  AnsiString(VLoc) + "," + AnsiString(ELink));
18970  THVPair Route2MultiMapKeyPair;
18971 
18972  Route2MultiMapKeyPair.first = HLoc;
18973  Route2MultiMapKeyPair.second = VLoc;
18974  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18975 
18976  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18977 
18978  if(ItPair.first == ItPair.second)
18979  {
18980  RouteNumber = -1;
18981  Utilities->CallLogPop(2032);
18982  return(false);
18983  }
18984  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18985  {
18986  RouteNumber = ItPair.first->second.first;
18987  Utilities->CallLogPop(2033);
18988  return(true);
18989  }
18990  ItPair.first++;
18991 
18992  if(ItPair.first == ItPair.second)
18993  {
18994  RouteNumber = -1;
18995  Utilities->CallLogPop(2034);
18996  return(false);
18997  }
18998  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18999  {
19000  RouteNumber = ItPair.first->second.first;
19001  Utilities->CallLogPop(2035);
19002  return(true);
19003  }
19004  RouteNumber = -1;
19005  Utilities->CallLogPop(2036);
19006  return(false);
19007 }
19008 
19009 // ---------------------------------------------------------------------------
19010 
19011 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
19012 /*
19013  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
19014  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
19015  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
19016  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
19017  Called by TAllRoutes::AddRouteElement.
19018 */
19019 {
19020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19021  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
19022  THVPair Route2MultiMapKeyPair;
19023 
19024  Route2MultiMapKeyPair.first = HLoc;
19025  Route2MultiMapKeyPair.second = VLoc;
19026  TRoute2MultiMapEntry Route2MultiMapEntry;
19027 
19028  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
19029  TRouteElementPair RouteElementPair;
19030 
19031  RouteElementPair.first = RouteNumber;
19032  RouteElementPair.second = RouteElementNumber;
19033  Route2MultiMapEntry.second = RouteElementPair;
19034 
19035  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
19036  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
19037  {
19038  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
19039  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
19040  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
19041  {
19042  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
19043  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
19044  {
19045  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19046  }
19047  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
19048  }
19049  else
19050  // same ELink so have an error
19051  {
19052  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19053  }
19054  }
19055  else
19056  {
19057  Route2MultiMap.insert(Route2MultiMapEntry);
19058  }
19059 // element at H&V not found in map so insert it
19060  Utilities->CallLogPop(399);
19061 }
19062 
19063 // ---------------------------------------------------------------------------
19064 
19066 /*
19067  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
19068  and the second in the reference SecondPair. If there's only one then it's the function return
19069 */
19070 {
19071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19072  AnsiString(VLoc));
19074 
19075  TempPair.first = -1;
19076  TempPair.second = 0;
19077  SecondPair = TempPair;
19078  TRoute2MultiMapIterator Route2MultiMapIterator;
19079  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
19080  THVPair Route2MultiMapKeyPair;
19081 
19082  Route2MultiMapKeyPair.first = HLoc;
19083  Route2MultiMapKeyPair.second = VLoc;
19084  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19085  {
19086  Utilities->CallLogPop(400);
19087  return(TempPair);
19088  }
19089  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19090  {
19091  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19092  Utilities->CallLogPop(401);
19093  return(Route2MultiMapIterator->second);
19094  }
19095  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19096  {
19097  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19098  TempPair = ItRange.first->second;
19099  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
19100  Utilities->CallLogPop(402);
19101  return(TempPair);
19102  }
19103  Utilities->CallLogPop(403);
19104  return(TempPair);
19105 }
19106 
19107 // ---------------------------------------------------------------------------
19108 
19109 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
19110 /*
19111  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
19112  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
19113 */
19114 {
19115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
19116  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
19117  {
19118  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
19119  {
19120  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
19121  TAllRoutes::TRouteElementPair SecondPair;
19122  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
19123  if(RouteElementPair.first == -1)
19124  // failed to find element in multimap
19125  {
19126  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
19127  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
19128  }
19129  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
19130  // neither pair has expected route number
19131  {
19132  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19133  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
19134  (AnsiString)Caller);
19135  }
19136  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
19137  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
19138  {
19139  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19140  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
19141  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
19142  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
19143  }
19144  }
19145  }
19146  unsigned int SizeVal = 0;
19147 
19148 // check map and sum of route sizes match
19149  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19150  {
19151  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
19152  }
19153  if(SizeVal != Route2MultiMap.size())
19154  {
19155  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
19156  (AnsiString)Caller);
19157  }
19158  Utilities->CallLogPop(404);
19159  return;
19160 }
19161 
19162 // ---------------------------------------------------------------------------
19163 
19164 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
19165 /*
19166  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
19167  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
19168  exceed that for the erased route. Where this is so the RouteNumber is decremented.
19169 */
19170 {
19171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
19172  if(!Route2MultiMap.empty())
19173  {
19174  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19175  {
19176  if(Route2MultiMapIterator->second.first > RouteNumber)
19177  {
19178  Route2MultiMapIterator->second.first--;
19179  }
19180  }
19181  }
19182  Utilities->CallLogPop(405);
19183 }
19184 
19185 // ---------------------------------------------------------------------------
19186 
19187 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
19188 /*
19189  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
19190  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
19191  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
19192 */
19193 {
19194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
19195  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
19196  if(!Route2MultiMap.empty())
19197  {
19198  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19199  {
19200  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
19201  {
19202  Route2MultiMapIterator->second.second--;
19203  }
19204  }
19205  }
19206  Utilities->CallLogPop(406);
19207 }
19208 
19209 // ---------------------------------------------------------------------------
19210 
19211 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
19212 /*
19213  Erases the route element from Route2MultiMap and from the PrefDirVector.
19214  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
19215  decremented if they are greater than the element number removed, and if the entire route is removed
19216  then the route numbers are also decremented in the map for route numbers that are greater than the route
19217  number that is removed.
19218 */
19219 {
19220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19221  AnsiString(ELink));
19222  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
19223  TRoute2MultiMapIterator Route2MultiMapIterator;
19224 
19225  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
19226  if(RequiredRoutePair.first == -1)
19227  {
19228  throw Exception("Failed to find route element in RemoveRouteElement");
19229  }
19230  Route2MultiMap.erase(Route2MultiMapIterator);
19231  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
19232 
19233 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
19234  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
19235 
19236  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
19237  {
19238  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
19239  }
19240 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
19241 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
19242 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
19243 // to check if a route element is present, and the element has already been removed from the map - see above.
19244 
19245 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
19246 /*
19247  int LockedVectorNumber = -1;
19248  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
19249  {
19250  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
19251  }
19252 */
19253 
19254 // erase element from route
19255  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
19256  RequiredRoutePair.second)));
19257 // CheckMapAndRoutes();//test - drop - tested below
19258 
19259 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
19260 // be so as continuation exit is at the end of the route, and truncation is from the end
19262  {
19264  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19265  AutoSigVectorIT--)
19266  {
19267  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
19268  {
19269  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
19270  }
19271  }
19272  }
19273 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
19274 // and adjust all the corresponding route numbers
19275  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
19276  {
19277  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
19278  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
19279  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
19280 
19281 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
19282  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
19283  it is erased then - see TInterface::ApproachLocking
19284 
19285  if(LockedVectorNumber > -1)
19286  {
19287  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
19288  }
19289 */
19290  // decrement route numbers in the locked route vector whether or not this route is a locked route
19291  if(!LockedRouteVector.empty())
19292  {
19293  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19294  {
19295  if(LRVIT->RouteNumber > RequiredRoutePair.first)
19296  {
19297  LRVIT->RouteNumber--;
19298  }
19299  }
19300  }
19302  {
19304  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19305  AutoSigVectorIT--)
19306  {
19307  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
19308  {
19309  AutoSigVectorIT->RouteNumber--;
19310  }
19311  }
19312  }
19313  }
19314  CheckMapAndRoutes(7); // test
19315  Utilities->CallLogPop(407);
19316 }
19317 
19318 // ---------------------------------------------------------------------------
19319 
19320 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
19321 /*
19322  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
19323  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
19324  since that catches all route elements wherever created
19325 */
19326 {
19327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19328  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
19329  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
19330  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
19331  Utilities->CallLogPop(408);
19332 }
19333 
19334 // ---------------------------------------------------------------------------
19335 
19336 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
19337 /*
19338  Enter with signal at TrackVectorElement already set to red by the passing train.
19339  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
19340  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
19341  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
19342  case the function sets no further signals.
19343 */
19344 {
19345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
19346  "," + AnsiString(XLinkPos));
19347  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
19348  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
19349 
19350  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
19351  if(RouteElementPair.first == -1)
19352  {
19353  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
19354  }
19355  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
19356 
19357  RequiredPair = RouteElementPair;
19358  if(RouteElement.XLinkPos != XLinkPos)
19359  {
19360  if(SecondPair.first != -1)
19361  {
19362  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
19363  RequiredPair = SecondPair;
19364  if(RouteElement.XLinkPos != XLinkPos)
19365  {
19366  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
19367  }
19368  }
19369  else
19370  {
19371  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
19372  }
19373  }
19374 // new function
19375  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
19376  Utilities->CallLogPop(409);
19377 }
19378 
19379 // ---------------------------------------------------------------------------
19380 
19381 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
19382 /*
19383  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
19384  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
19385  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
19386  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
19387  to 2 for successive calls.
19388  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
19389  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
19390  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
19391  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
19392 */
19393 {
19394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
19395  AnsiString(AccessNumber));
19396  TPrefDirElement RouteElement;
19397  int Attribute = AccessNumber + 1;
19398 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
19399  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
19400 
19401  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
19402  {
19403  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
19404  }
19405  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
19406  {
19407  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
19408  }
19409  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
19410  x).XLinkPos] != End)
19411  {
19412  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
19413  }
19414 // new function
19415  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
19416  Utilities->CallLogPop(410);
19417 }
19418 
19419 // ---------------------------------------------------------------------------
19420 
19421 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
19422 /*
19423  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
19424  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
19425  or (b) in a linked rear route, in which case the function sets no further signals.
19426 
19427  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
19428  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
19429  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
19430  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
19431  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
19432  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
19433  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
19434  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
19435  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
19436  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
19437  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
19438  found behind the train.
19439 
19440  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
19441  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
19442  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
19443  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
19444  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
19445  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
19446  a route.
19447 
19448  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
19449  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
19450  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
19451  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
19452  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
19453  reference. If no train is found before the beginning of the route is reached the function returns true
19454 
19455 */
19456 {
19457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
19458  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
19459  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
19460  int RearwardLinkedRouteNumber;
19461 
19462  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
19463  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
19464  // signal value in the route for use in further linked routes
19465  {
19466  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
19467  {
19468  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19469  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
19470  {
19471  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
19472  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
19473  {
19474  break;
19475  }
19476  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
19477  // flash LCs on those routes
19478  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
19479  }
19480  }
19481  }
19482  else
19483  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
19484  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
19485  {
19486  int TrainID, TrainPosition, BehindTrainPosition;
19487  bool FoundTrain = false, BehindTrain = false;
19488  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
19489  {
19490  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
19491  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
19492  TrainID = TrackElement.TrainIDOnElement;
19493  if(TrackElement.TrackType == Bridge)
19494  {
19495  if(PrefDirElement.XLinkPos < 2)
19496  {
19497  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19498  }
19499  else
19500  {
19501  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19502  }
19503  }
19504  if(TrainID == -1)
19505  {
19506  continue;
19507  }
19508  else
19509  {
19510  FoundTrain = true;
19511  TrainPosition = x;
19512  break;
19513  }
19514  }
19515  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
19516  {
19517  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
19518  {
19519  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
19520  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
19521  // need the element behind the rearmost train.
19522  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
19523  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
19524  TrainID = TrackElement.TrainIDOnElement;
19525  if(TrackElement.TrackType == Bridge)
19526  {
19527  if(PrefDirElement.XLinkPos < 2)
19528  {
19529  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19530  }
19531  else
19532  {
19533  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19534  }
19535  }
19536  if(TrainID != -1)
19537  {
19538  continue; // still on train
19539  }
19540  else
19541  {
19542  BehindTrain = true;
19543  BehindTrainPosition = x;
19544  break;
19545  }
19546  }
19547  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
19548  // so on for as many trains as there are on the single route
19549  {
19550  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
19551  // first signal behind train to be red
19552  }
19553  }
19554  }
19555  Utilities->CallLogPop(411);
19556 }
19557 
19558 // ---------------------------------------------------------------------------
19559 
19560 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
19561 {
19562 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
19563  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
19564  first signal is red, then OK
19565 */
19566  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
19567  AnsiString(RouteTruncatePosition));
19568  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
19569  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
19570  TPrefDirElement PrefDirElement, FirstElement;
19571  TTrackElement TrackElement;
19572  bool ExamineRoute = true;
19573 
19574  while(ExamineRoute)
19575  {
19576  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
19577  {
19578  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
19579  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
19580  TrainID = TrackElement.TrainIDOnElement;
19581  if(TrackElement.TrackType == Bridge)
19582  {
19583  if(PrefDirElement.XLinkPos < 2)
19584  {
19585  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19586  }
19587  else
19588  {
19589  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19590  }
19591  }
19592  if(TrainID > -1)
19593  {
19594  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
19595  {
19596  //any trains further back in route will be protected by the red signal behind the stopped train
19597  Utilities->CallLogPop(412);
19598  return(false);
19599  }
19600  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
19601  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
19602  //other way & can cancel the route
19603  {
19604  Utilities->CallLogPop(2203);
19605  return(false);
19606  }
19607  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
19608  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
19609  }
19610  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
19611  {
19612  if(TrackElement.Attribute == 0)
19613  {
19614  Utilities->CallLogPop(413);
19615  return(false); // OK, red signal in front of a train
19616  }
19617  SignalCount++;
19618  if(SignalCount >= 3)
19619  {
19620  Utilities->CallLogPop(414);
19621  return(false);
19622  }
19623  }
19624  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
19625  // ElinkPos because working back along PrefDir to beginning
19626  {
19627  Utilities->CallLogPop(415);
19628  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
19629  }
19630  }
19631  //now look at linked rearwards routes
19632  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
19633  StartPosition = CurrentRoute.PrefDirSize() - 1;
19634  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19635  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
19636  {
19637  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
19638  ExamineRoute = true;
19639  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
19640  }
19641  else
19642  {
19643  // here check for a train on the element immediately before the first route element
19644  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
19645  TrainID = PriorTrackElement.TrainIDOnElement;
19646  if(PriorTrackElement.TrackType == Bridge)
19647  {
19648  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
19649  {
19650  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19651  }
19652  else
19653  {
19654  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19655  }
19656  }
19657  if(TrainID > -1)
19658  {
19659  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
19660  {
19661  Utilities->CallLogPop(748);
19662  return(false);
19663  }
19664  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
19665  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
19666  //other way & can cancel the route
19667  {
19668  Utilities->CallLogPop(2204);
19669  return(false);
19670  }
19671  Utilities->CallLogPop(1962);
19672  return(true); //otherwise need to lock the route
19673  }
19674  ExamineRoute = false;
19675  }
19676  }
19677 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
19678 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
19679  Utilities->CallLogPop(416);
19680  return(false);
19681 }
19682 
19683 // ---------------------------------------------------------------------------
19684 
19685 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
19686  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
19687 {
19688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
19689  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
19690  TPrefDirElement InternalPrefDirElement; // blank element
19691 
19692  PrefDirElement = InternalPrefDirElement;
19693  if(LockedRouteVector.empty())
19694  {
19695  Utilities->CallLogPop(417);
19696  return(false);
19697  }
19698 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
19699 // even if some elements have been removed from the front by a train
19700  bool InLockedRoute = false;
19701 
19702  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19703  {
19704  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
19705  {
19706  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
19707  // doesn't arise)
19708  InLockedRoute = true;
19709  break;
19710  }
19711  }
19712  if(!InLockedRoute)
19713  {
19714  Utilities->CallLogPop(418);
19715  return(false);
19716  }
19717  int RouteNumber, VectorCount = 0;
19718  TRouteType RouteType;
19719 
19720  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19721  {
19722  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
19723  if(RouteType == NoRoute)
19724  {
19725  continue;
19726  }
19727  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
19728  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
19729  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
19730  {
19731  throw Exception
19732  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
19733  }
19734  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
19735  {
19736  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
19737  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
19738  {
19739  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19740  {
19741  PrefDirElement = InternalPrefDirElement;
19742  LockedVectorNumber = VectorCount;
19743  Utilities->CallLogPop(419);
19744  return(true);
19745  }
19746  }
19747  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
19748  {
19749  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19750  {
19751  PrefDirElement = InternalPrefDirElement;
19752  LockedVectorNumber = VectorCount;
19753  Utilities->CallLogPop(420);
19754  return(true);
19755  }
19756  else
19757  {
19758  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
19759  }
19760  }
19761  }
19762  VectorCount++;
19763  }
19764  Utilities->CallLogPop(421);
19765  return(false);
19766 }
19767 
19768 // ---------------------------------------------------------------------------
19769 
19771 {
19772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
19773  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19774  {
19775  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
19776  {
19777  Utilities->CallLogPop(963);
19778  return(x);
19779  }
19780  }
19781  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
19782 }
19783 
19784 // ---------------------------------------------------------------------------
19785 
19787 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
19788 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
19789 {
19790  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19791  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19792  {
19793  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
19794  {
19795  Utilities->CallLogPop(2039);
19796  return(true);
19797  }
19798  }
19799  Utilities->CallLogPop(2040);
19800  return(false);
19801 }
19802 
19803 // ---------------------------------------------------------------------------
19804 
19806 {
19807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19808  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19809  {
19810  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
19811  {
19812  Utilities->CallLogPop(964);
19813  return(GetFixedRouteAt(159, x));
19814  }
19815  }
19816  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19817 }
19818 
19819 // ---------------------------------------------------------------------------
19820 
19822 {
19823  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
19824  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19825  {
19826  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
19827  {
19828  Utilities->CallLogPop(965);
19829  return(GetModifiableRouteAt(15, x));
19830  }
19831  }
19832  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19833 }
19834 
19835 // ---------------------------------------------------------------------------
19836 
19837 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
19838 {
19839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
19840  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
19841  Utilities->SaveFileInt(OutFile, NextRouteID);
19842  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19843  {
19844  TOneRoute OneRoute = GetFixedRouteAt(165, x);
19845  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
19846  OneRoute.SavePrefDirVector(6, OutFile);
19847  }
19848  Utilities->CallLogPop(1442);
19849 }
19850 
19851 // ---------------------------------------------------------------------------
19852 
19853 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
19854 {
19855  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
19856  int NumberOfRoutes;
19857 
19858  NumberOfRoutes = Utilities->LoadFileInt(InFile);
19859  NextRouteID = Utilities->LoadFileInt(InFile);
19860  for(int x = 0; x < NumberOfRoutes; x++)
19861  {
19862  TOneRoute OneRoute; // empty route
19863  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
19864  OneRoute.LoadPrefDir(2, InFile);
19866  {
19867  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19868  }
19869  else
19870  {
19871  Utilities->CallLogPop(1443);
19872  return(false);
19873  }
19874  }
19875  Utilities->CallLogPop(1444);
19876  return(true);
19877 }
19878 
19879 // ---------------------------------------------------------------------------
19880 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19881 {
19882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19883  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19884 
19885  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19886  {
19887  Utilities->CallLogPop(1445);
19888  return(false);
19889  }
19890  int NextID = Utilities->LoadFileInt(InFile);
19891 
19892  if((NextID < 0) || (NextID > 1000000))
19893  {
19894  Utilities->CallLogPop(1446);
19895  return(false);
19896  }
19897  for(int x = 0; x < NumberOfRoutes; x++)
19898  {
19899  int RouteID = Utilities->LoadFileInt(InFile);
19900  if((RouteID < 0) || (RouteID > 20000))
19901  {
19902  Utilities->CallLogPop(1447);
19903  return(false);
19904  }
19905  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19906  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19907  {
19908  Utilities->CallLogPop(1448);
19909  return(false);
19910  }
19911  }
19912  Utilities->CallLogPop(1449);
19913  return(true);
19914 }
19915 
19916 // ---------------------------------------------------------------------------
19917 
19918 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19919 {
19920  // return true for a loop
19921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19922  AnsiString(StartPosition));
19923  if(EndPosition == StartPosition)
19924  {
19925  Utilities->CallLogPop(1839);
19926  return(true); // shouldn't happen but treat as a loop if does
19927  }
19928 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19929  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19930  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19931 
19932  while(TrackIsInARoute(15, TVPos, LkPos))
19933  {
19934  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19935  int NewLkPos = -1;
19936  if(NewTVPos > -1)
19937  {
19938  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19939  if(NewLkPos == -1)
19940  {
19941  Utilities->CallLogPop(1840);
19942  return(true); // shouldn't arise but treat as loop if does
19943  }
19944  }
19945  else // reached a buffer or continuation
19946  {
19947  Utilities->CallLogPop(1841);
19948  return(false);
19949  }
19950 //Error found by Xeon notified by email 13/10/20.
19951 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19952 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19953 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19954 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19955 //New check added for v2.6.0
19956 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19957 //as possible in case there are other unforeseen effects.
19958  int RouteNumber; //dummy, not used
19959  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19960  {
19961  Utilities->CallLogPop(2241);
19962  return(false);
19963  }
19964  //now make the connected element the current element, read across the TV number and determine the exit link
19965  TVPos = NewTVPos;
19966  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19967  {
19968  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19969  {
19970  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19971  {
19972  LkPos = 1;
19973  }
19974  else
19975  {
19976  LkPos = 3;
19977  }
19978  }
19979  else
19980  {
19981  LkPos = 0;
19982  }
19983  }
19984  else
19985  {
19986  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19987  }
19988  if(TVPos == StartPosition)
19989  {
19990  Utilities->CallLogPop(1842);
19991  return(true); // it is a loop
19992  }
19993  }
19994  Utilities->CallLogPop(1843);
19995  return(false); // reached end of route so not a loop
19996 }
19997 
19998 // ---------------------------------------------------------------------------
19999 
20000 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20001 /*
20002  Track geometry allows diagonals to cross without occupying the same track element, so when
20003  route plotting it is necessary to check if there is an existing route or a train on such a crossing
20004  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
20005  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20006  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20007  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20008  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20009  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20010  Each of these is examined in turn for each route element in the relevant position.
20011 
20012  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
20013  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
20014  that returns false in all cases (including elements & links not present) except train present.
20015 */
20016 {
20017  int TrainID; // not used in this function
20018 
20019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
20020  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
20021  TPrefDirElement TempPrefDirElement;
20022  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20023 
20024  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
20025  if(FirstPair.first > -1)
20026  {
20027  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
20028  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20029  {
20030  Utilities->CallLogPop(310);
20031  return(true);
20032  }
20033  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20034  {
20035  Utilities->CallLogPop(311);
20036  return(true);
20037  }
20038  }
20039  if(SecondPair.first > -1)
20040  {
20041  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
20042  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20043  {
20044  Utilities->CallLogPop(312);
20045  return(true);
20046  }
20047  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20048  {
20049  Utilities->CallLogPop(313);
20050  return(true);
20051  }
20052  }
20053  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
20054  9, TrainID)))
20055  {
20056  Utilities->CallLogPop(1997);
20057  return(true);
20058  }
20059  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
20060  if(FirstPair.first > -1)
20061  {
20062  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
20063  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20064  {
20065  Utilities->CallLogPop(314);
20066  return(true);
20067  }
20068  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20069  {
20070  Utilities->CallLogPop(315);
20071  return(true);
20072  }
20073  }
20074  if(SecondPair.first > -1)
20075  {
20076  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
20077  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20078  {
20079  Utilities->CallLogPop(316);
20080  return(true);
20081  }
20082  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20083  {
20084  Utilities->CallLogPop(317);
20085  return(true);
20086  }
20087  }
20088  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
20089  9, TrainID)))
20090  {
20091  Utilities->CallLogPop(1998);
20092  return(true);
20093  }
20094  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
20095  if(FirstPair.first > -1)
20096  {
20097  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
20098  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20099  {
20100  Utilities->CallLogPop(318);
20101  return(true);
20102  }
20103  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20104  {
20105  Utilities->CallLogPop(319);
20106  return(true);
20107  }
20108  }
20109  if(SecondPair.first > -1)
20110  {
20111  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
20112  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20113  {
20114  Utilities->CallLogPop(320);
20115  return(true);
20116  }
20117  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20118  {
20119  Utilities->CallLogPop(321);
20120  return(true);
20121  }
20122  }
20123  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
20124  7, TrainID)))
20125  {
20126  Utilities->CallLogPop(1999);
20127  return(true);
20128  }
20129  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
20130  if(FirstPair.first > -1)
20131  {
20132  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
20133  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20134  {
20135  Utilities->CallLogPop(322);
20136  return(true);
20137  }
20138  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20139  {
20140  Utilities->CallLogPop(323);
20141  return(true);
20142  }
20143  }
20144  if(SecondPair.first > -1)
20145  {
20146  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
20147  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20148  {
20149  Utilities->CallLogPop(324);
20150  return(true);
20151  }
20152  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20153  {
20154  Utilities->CallLogPop(325);
20155  return(true);
20156  }
20157  }
20158  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
20159  3, TrainID)))
20160  {
20161  Utilities->CallLogPop(2000);
20162  return(true);
20163  }
20164  Utilities->CallLogPop(326);
20165  return(false);
20166 }
20167 
20168 // ---------------------------------------------------------------------------
20169 
20170 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20171 /*
20172  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
20173  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20174  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20175  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20176  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20177  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20178  Each of these is examined in turn for each route element in the relevant position.
20179 */
20180 {
20181  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20182  "," + AnsiString(DiagonalLinkNumber));
20183  TPrefDirElement TempPrefDirElement;
20184  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20185 
20186  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
20187  if(FirstPair.first > -1)
20188  {
20189  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
20190  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20191  {
20192  Utilities->CallLogPop(2010);
20193  return(true);
20194  }
20195  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20196  {
20197  Utilities->CallLogPop(2011);
20198  return(true);
20199  }
20200  }
20201  if(SecondPair.first > -1)
20202  {
20203  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
20204  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20205  {
20206  Utilities->CallLogPop(2012);
20207  return(true);
20208  }
20209  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20210  {
20211  Utilities->CallLogPop(2013);
20212  return(true);
20213  }
20214  }
20215  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
20216  if(FirstPair.first > -1)
20217  {
20218  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
20219  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20220  {
20221  Utilities->CallLogPop(2014);
20222  return(true);
20223  }
20224  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20225  {
20226  Utilities->CallLogPop(2015);
20227  return(true);
20228  }
20229  }
20230  if(SecondPair.first > -1)
20231  {
20232  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
20233  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20234  {
20235  Utilities->CallLogPop(2016);
20236  return(true);
20237  }
20238  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20239  {
20240  Utilities->CallLogPop(2017);
20241  return(true);
20242  }
20243  }
20244  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
20245  if(FirstPair.first > -1)
20246  {
20247  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
20248  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20249  {
20250  Utilities->CallLogPop(2018);
20251  return(true);
20252  }
20253  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20254  {
20255  Utilities->CallLogPop(2019);
20256  return(true);
20257  }
20258  }
20259  if(SecondPair.first > -1)
20260  {
20261  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
20262  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20263  {
20264  Utilities->CallLogPop(2020);
20265  return(true);
20266  }
20267  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20268  {
20269  Utilities->CallLogPop(2021);
20270  return(true);
20271  }
20272  }
20273  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
20274  if(FirstPair.first > -1)
20275  {
20276  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
20277  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20278  {
20279  Utilities->CallLogPop(2022);
20280  return(true);
20281  }
20282  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20283  {
20284  Utilities->CallLogPop(2023);
20285  return(true);
20286  }
20287  }
20288  if(SecondPair.first > -1)
20289  {
20290  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
20291  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20292  {
20293  Utilities->CallLogPop(2024);
20294  return(true);
20295  }
20296  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20297  {
20298  Utilities->CallLogPop(2025);
20299  return(true);
20300  }
20301  }
20302  Utilities->CallLogPop(2026);
20303  return(false);
20304 }
20305 
20306 // ---------------------------------------------------------------------------
20307 
20308 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9229
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:695
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:480
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18415
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1319
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:952
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:467
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11655
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:681
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:748
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:631
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:583
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11628
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:436
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4746
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:570
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:356
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:893
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5601
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13173
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:790
TFixedTrackPiece
Definition: TrackUnit.h:82
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1730
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:811
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:943
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:19011
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:809
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:944
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10110
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:811
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:19421
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:955
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1373
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:512
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:803
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:599
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:720
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13697
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:777
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:638
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:821
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:434
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13213
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:697
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3780
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:718
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:398
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:457
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:899
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:801
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:285
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7356
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1647
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17806
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:470
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:96
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:702
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1710
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:727
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5753
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7257
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5780
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1529
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:590
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1671
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:844
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:865
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1946
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10444
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:927
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:620
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:17537
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:630
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:941
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:20170
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:436
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1701
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:611
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2842
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:487
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:555
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5933
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:746
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:690
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:463
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8284
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1539
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:649
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:18849
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:781
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:582
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:684
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12952
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:363
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7742
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:486
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:404
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10512
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9488
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14346
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:16129
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:584
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:18375
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:19211
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:875
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:759
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:873
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:497
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1651
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:891
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:551
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12756
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:160
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:516
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4501
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3680
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:691
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:849
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1551
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:462
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:600
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:778
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:469
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:814
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8099
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:442
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:680
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:603
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4661
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1333
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6540
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10933
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:672
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:928
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:520
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:926
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:886
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3556
Unused
@ Unused
Definition: TrackUnit.h:65
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:605
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:635
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1332
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:493
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:723
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:19685
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2875
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:788
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7728
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:924
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:226
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19880
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:578
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9655
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1709
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1549
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1638
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:208
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:953
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:729
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:440
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:838
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:817
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3280
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16058
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:795
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:687
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:503
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8551
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13018
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:805
Simple
@ Simple
Definition: TrackUnit.h:65
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:447
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:76
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:481
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:812
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2891
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:729
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1041
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18959
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:793
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:837
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:428
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1400
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:724
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13269
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3877
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1752
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:613
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5893
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:688
TTrain
Definition: TrainUnit.h:304
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:742
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:380
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14217
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:507
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11669
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:496
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:579
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:574
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:860
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:630
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7757
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:419
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:88
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:350
GapJump
@ GapJump
Definition: TrackUnit.h:65
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:446
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:808
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:19320
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:874
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7503
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:475
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:956
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:461
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::Raising
@ Raising
Definition: TrackUnit.h:611
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:646
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:572
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10549
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1553
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1517
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:716
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:369
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:702
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:584
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:807
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:389
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:779
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:456
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:733
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1409
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6164
End
@ End
Definition: TrackUnit.h:75
TUserGraphicItem
Definition: DisplayUnit.h:31
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:71
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1555
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:686
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:622
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8905
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:882
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:939
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:567
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10658
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1054
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:303
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:818
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:745
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:813
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:596
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:949
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:741
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:495
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:776
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3851
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1025
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:872
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1026
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:230
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:528
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:719
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9620
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1035
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:465
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:18363
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:506
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:796
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1675
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:810
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:845
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7771
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:925
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:460
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:672
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:407
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6949
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:647
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:228
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:494
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:703
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:920
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8944
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:942
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:835
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:18348
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:774
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:590
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:675
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:825
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:819
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:74
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13986
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13723
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:732
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:925
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:64
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:506
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4586
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1896
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:431
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:832
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:437
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:847
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:484
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:612
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:822
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:434
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:498
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:785
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:476
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:93
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:434
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:834
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:593
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11136
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:19164
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4840
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:160
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1915
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:795
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:692
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:807
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:960
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:761
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:562
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:604
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:738
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:853
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:657
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11381
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:19786
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:590
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1052
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:629
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2859
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:728
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1561
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15221
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7384
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8741
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7463
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:685
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:739
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5804
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:694
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:678
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:317
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:685
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1335
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:872
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:821
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:513
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:820
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:473
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13357
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:784
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:885
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12492
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1676
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1728
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:45
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:940
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:606
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:791
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12985
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:712
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:670
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:18014
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3657
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13676
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11424
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10799
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1798
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:782
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:937
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:499
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:581
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5987
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12805
Under
@ Under
Definition: TrackUnit.h:75
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:453
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:825
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:714
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:626
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2914
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11681
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12000
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:889
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:431
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10693
Lead
@ Lead
Definition: TrackUnit.h:75
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:118
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5852
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1832
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13924
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6064
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:891
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5644
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6521
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:85
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:94
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1364
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9416
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:471
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:472
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:597
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:711
TTrack::Up
@ Up
Definition: TrackUnit.h:611
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:881
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:827
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:585
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10672
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:959
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1511
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8708
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1669
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:757
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:204
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:18081
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1658
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:366
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:799
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6407
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:478
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:449
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:829
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:641
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8654
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:801
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:576
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7412
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10083
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:455
Signal
@ Signal
Definition: TrackUnit.h:75
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:572
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:590
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:464
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:793
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18652
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1566
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12855
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:509
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11320
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4670
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:570
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10644
TGraphicElement::Width
int Width
Definition: TrackUnit.h:438
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:19560
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:523
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:19770
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:18478
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:799
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:491
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:795
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:588
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:450
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:789
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14755
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:659
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4159
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2377
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:692
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:468
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9556
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:12623
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:607
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:791
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:410
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:880
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:964
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5828
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19853
FNil
@ FNil
Definition: Utilities.h:42
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:586
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1553
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:946
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:787
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1542
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:846
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7110
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:474
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:763
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1065
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1067
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:517
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7943
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:18173
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:660
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:425
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7485
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:803
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:850
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:401
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:483
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5449
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:825
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1708
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:830
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:877
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:594
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13746
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:618
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11232
Parapet
@ Parapet
Definition: TrackUnit.h:66
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:451
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:18322
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:114
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:804
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1029
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:273
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9225
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:18146
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:381
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:870
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:825
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:19187
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:609
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:951
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:797
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:802
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:482
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:825
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:553
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:921
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1070
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:737
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:817
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:15728
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:842
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:206
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11452
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:12550
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:508
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1313
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:500
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:919
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:18109
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:615
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:923
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:479
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:750
TTrack
Definition: TrackUnit.h:548
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1372
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:872
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1403
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:19336
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1645
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8253
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:639
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:588
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:859
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:669
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:745
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:868
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:824
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:519
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:704
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:204
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:18827
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:931
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:212
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2994
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:454
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9777
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:945
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6301
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2129
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:587
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:743
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:160
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:166
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:863
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:805
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2595
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:202
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1643
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7907
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:485
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12338
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13116
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:586
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1517
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10581
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8617
IDInt
Definition: TrackUnit.h:497
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2594
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:592
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:19821
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:616
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:797
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4474
TDisplay
Definition: DisplayUnit.h:48
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:929
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10331
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:918
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5194
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:867
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:791
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:840
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:440
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19918
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1126
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9339
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:570
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7854
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1314
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:140
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:905
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13426
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:781
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:749
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:384
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:650
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:210
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:396
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:866
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14552
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1713
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:786
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7822
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:632
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:827
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:800
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:734
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:907
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:773
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1528
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:857
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1649
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:854
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1659
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:440
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4762
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:589
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9165
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:708
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15864
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1342
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:735
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:434
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13852
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:831
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1320
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13627
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:721
Points
@ Points
Definition: TrackUnit.h:65
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:742
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18900
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:872
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10014
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11303
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:413
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:601
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:839
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:502
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4181
Trail
@ Trail
Definition: TrackUnit.h:75
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:18058
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9398
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:17629
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:780
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1868
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:501
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:823
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:17385
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:836
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:666
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:422
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:744
Continuation
@ Continuation
Definition: TrackUnit.h:65
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1061
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7701
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3757
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6084
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:13524
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:590
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:359
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9445
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:871
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:879
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:887
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12381
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:576
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:841
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:771
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:876
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:713
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:434
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:590
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1050
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:791
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3374
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:438
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:892
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1545
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:459
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:707
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:675
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:739
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1707
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:947
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:372
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:267
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:747
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:855
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:20000
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:490
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13321
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1039
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:488
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:785
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1519
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1043
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:353
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:452
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:787
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:634
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:901
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:932
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4729
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:890
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:18798
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1740
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8755
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:717
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:696
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:595
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:809
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:671
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:11090
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:829
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:707
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1374
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:18200
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:714
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19837
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:580
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1878
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4712
Connection
@ Connection
Definition: TrackUnit.h:75
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:930
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3734
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:362
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1715
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9677
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1030
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:751
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:504
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17198
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:11610
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12199
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:725
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:828
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8681
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:11582
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:878
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1048
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:19109
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:19065
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7183
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10961
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:710
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:869
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:733
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1401
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:902
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:489
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:17449
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5872
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:862
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:726
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:448
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:154
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:434
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:771
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10137
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:572
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:735
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:749
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:18335
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4872
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:806
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2770
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:693
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7782
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:390
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3136
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:378
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:858
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:883
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:375
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:17356
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:628
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14116
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:352
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:769
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:608
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:693
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:70
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11520
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:632
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:397
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:492
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1314
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:654
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:466
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:922
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:664
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:935
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:643
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11760
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:458
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:434
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:518
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:954
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1515
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:199
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8804
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:816
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:522
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1776
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8986
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:92
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:644
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:590
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:723
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13823
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:19805
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:610
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1371
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4372
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:815
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4603
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7645
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1973
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:529
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1056
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6447
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1027
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:713
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:843
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:645
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:917
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7440
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1403
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:212
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:666
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:888
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:779
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:704
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4628
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:789
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1653
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1063
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:783
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11552
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:957
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8204
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:683
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1327
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:813
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:848
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9594
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1037
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:772
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11197
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1783
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:833
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:104
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:642
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1517
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:351
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16285
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7628
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:819
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:798
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:696
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1519
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:615
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6464
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:727
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3634
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:775
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:661
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:583
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:805
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:755
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11123
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:792
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:884
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16701
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:852
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:40
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:680
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:948
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:712
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:624
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:731
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:416
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:585
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:687
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:823
RouteCall
@ RouteCall
Definition: TrackUnit.h:1320
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:391
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11694
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:864
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:90
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:610
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:505
NotSet
@ NotSet
Definition: TrackUnit.h:75
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:670
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:19381
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:394
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:611
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:598
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:742
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11152
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10413
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:675
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:202
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:794
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:950
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6365
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:160
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:958
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15257
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:747
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11706
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1376
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:395
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1548
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:856
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:740
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:826
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:711
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:572
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:633
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10404
Bridge
@ Bridge
Definition: TrackUnit.h:65
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:867
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:443
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1314
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:815
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:527
Gap
@ Gap
Definition: TrackUnit.h:75
Buffers
@ Buffers
Definition: TrackUnit.h:65
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17114
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:708
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:98
CrossConn
@ CrossConn
Definition: TrackUnit.h:75
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11718
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:477
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4540
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11641
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:851